Qual loop tem melhor desempenho? Por quê?

String s = ""; for(i=0;i<....){ s = some Assignment; } 

ou

 for(i=0;i<..){ String s = some Assignment; } 

Eu não preciso usar ‘s’ fora do loop novamente. A primeira opção talvez seja melhor, já que uma nova String não é inicializada a cada vez. A segunda, no entanto, resultaria no escopo da variável ser limitada ao loop em si.

EDIT: Em resposta a resposta do Milhous. Seria inútil atribuir a String a uma constante dentro de um loop, não é? Não, aqui ‘alguma atribuição’ significa que um valor variável obtido da lista é iterado.

Além disso, a questão não é porque estou preocupado com o gerenciamento de memory. Só quero saber qual é o melhor.

Âmbito limitado é melhor

Use sua segunda opção:

 for ( ... ) { String s = ...; } 

O escopo não afeta o desempenho

Se você desmontar o código compilado de cada um (com a ferramenta javap do JDK), você verá que o loop compila exatamente as mesmas instruções da JVM em ambos os casos. Note também que a “Opção # 3” de Brian R. Bondy é idêntica à Opção # 1. Nada extra é adicionado ou removido da pilha ao usar o escopo mais apertado, e os mesmos dados são usados ​​na pilha em ambos os casos.

Evite a Inicialização Prematura

A única diferença entre os dois casos é que, no primeiro exemplo, a variável s é desnecessariamente inicializada. Este é um problema separado da localização da declaração da variável. Isso adiciona duas instruções desperdiçadas (para carregar uma constante de seqüência de caracteres e armazená-lo em um slot de quadro de pilha). Uma boa ferramenta de análise estática irá avisá-lo de que você nunca está lendo o valor atribuído a s , e um bom compilador JIT provavelmente o elimina em tempo de execução.

Você poderia consertar isso simplesmente usando uma declaração vazia (ou seja, String s; ), mas isso é considerado uma má prática e tem outro efeito colateral discutido abaixo.

Muitas vezes, um valor falso, como null é atribuído a uma variável simplesmente para silenciar um erro do compilador de que uma variável é lida sem ser inicializada. Esse erro pode ser considerado como uma sugestão de que o escopo da variável é muito grande e que está sendo declarado antes de ser necessário receber um valor válido. Declarações vazias forçam você a considerar cada caminho de código; não ignore este aviso valioso, atribuindo um valor falso.

Conserve Slots de Pilha

Conforme mencionado, embora as instruções da JVM sejam as mesmas em ambos os casos, há um efeito colateral sutil que torna melhor, no nível da JVM, usar o escopo mais limitado possível. Isso é visível na “tabela de variables ​​locais” do método. Considere o que acontece se você tiver vários loops, com as variables ​​declaradas no escopo desnecessariamente grande:

 void x(String[] strings, Integer[] integers) { String s; for (int i = 0; i < strings.length; ++i) { s = strings[0]; ... } Integer n; for (int i = 0; i < integers.length; ++i) { n = integers[i]; ... } } 

As variables s e n podem ser declaradas dentro de seus respectivos loops, mas como não são, o compilador usa dois "slots" no quadro da pilha. Se eles foram declarados dentro do loop, o compilador pode reutilizar o mesmo slot, tornando o quadro de pilha menor.

O que realmente importa

No entanto, a maioria dessas questões é imaterial. Um bom compilador JIT verá que não é possível ler o valor inicial que você está atribuindo com desperdício e otimizar a atribuição. Salvando um slot aqui ou ali não vai fazer ou quebrar seu aplicativo.

O importante é tornar seu código legível e fácil de manter e, nesse aspecto, usar um escopo limitado é claramente melhor. Quanto menor o escopo de uma variável, mais fácil é compreender como ela é usada e o impacto que qualquer alteração no código terá.

Em teoria , é um desperdício de resources declarar a cadeia dentro do loop. Na prática , no entanto, ambos os trechos que você apresentou compilarão para o mesmo código (declaração fora do loop).

Portanto, se o seu compilador fizer alguma otimização, não haverá diferença.

Em geral, eu escolheria o segundo, porque o escopo da variável ‘s’ é limitado ao loop. Benefícios:

  • Isso é melhor para o programador porque você não precisa se preocupar com ‘ser’ usado novamente em algum lugar mais tarde na function
  • Isso é melhor para o compilador porque o escopo da variável é menor e, portanto, pode potencialmente fazer mais análise e otimização
  • Isso é melhor para os futuros leitores porque eles não se perguntarão por que a variável ‘s’ é declarada fora do loop se nunca for usada depois

Se você quiser acelerar loops, prefiro declarar uma variável max ao lado do contador para que não sejam necessárias pesquisas repetidas para a condição:

ao invés de

 for (int i = 0; i < array.length; i++) { Object next = array[i]; } 

eu prefiro

 for (int i = 0, max = array.lenth; i < max; i++) { Object next = array[i]; } 

Quaisquer outras coisas que devam ser consideradas já foram mencionadas, então apenas meus dois centavos (veja ericksons post)

Greetz, GHad

Para adicionar um pouco à resposta do @ Esteban Araya , ambos irão requerer a criação de uma nova string a cada vez através do loop (como o valor de retorno da expressão some Assignment ). Essas strings precisam ser coletadas de qualquer maneira.

Eu sei que esta é uma pergunta antiga, mas eu pensei em adicionar um pouco que seja um pouco relacionado.

Eu observei enquanto navegava no código-fonte Java que alguns methods, como String.contentEquals (duplicados abaixo), fazem variables ​​locais redundantes que são meramente cópias de variables ​​de class. Eu acredito que houve um comentário em algum lugar, que implicava que acessar variables ​​locais é mais rápido do que acessar variables ​​de class.

Neste caso, “v1” e “v2” são aparentemente desnecessários e podem ser eliminados para simplificar o código, mas foram adicionados para melhorar o desempenho.

 public boolean contentEquals(StringBuffer sb) { synchronized(sb) { if (count != sb.length()) return false; char v1[] = value; char v2[] = sb.getValue(); int i = offset; int j = 0; int n = count; while (n-- != 0) { if (v1[i++] != v2[j++]) return false; } } return true; } 

Parece-me que precisamos de mais especificação do problema.

o

 s = some Assignment; 

não está especificado quanto ao tipo de atribuição. Se a tarefa for

 s = "" + i + ""; 

então uma nova picada precisa ser alocada.

mas se é

 s = some Constant; 

s indicará apenas a localização da memory das constantes e, assim, a primeira versão seria mais eficiente na memory.

Parece pouco bobo se preocupar com muita otimização de um loop for para um interpretado lang IMHO.

Quando eu estou usando vários threads (50+), então eu achei que esta é uma maneira muito eficaz de lidar com problemas de thread fantasma com não ser capaz de fechar um processo corretamente …. se eu estiver errado, por favor, deixe-me saber por que Estou errado:

 Process one; BufferedInputStream two; try{ one = Runtime.getRuntime().exec(command); two = new BufferedInputStream(one.getInputStream()); } }catch(e){ e.printstacktrace } finally{ //null to ensure they are erased one = null; two = null; //nudge the gc System.gc(); }