Diferença entre declarar variáveis ​​antes ou em loop?


312

Sempre me perguntei se, em geral, declarar uma variável descartável antes de um loop, em vez de repetidamente dentro do loop, faz alguma diferença (de desempenho)? Um exemplo (bastante inútil) em Java:

a) declaração antes do loop:

double intermediateResult;
for(int i=0; i < 1000; i++){
    intermediateResult = i;
    System.out.println(intermediateResult);
}

b) declaração (repetidamente) loop interno:

for(int i=0; i < 1000; i++){
    double intermediateResult = i;
    System.out.println(intermediateResult);
}

Qual é o melhor, a ou b ?

Suspeito que a declaração variável repetida (exemplo b ) crie mais sobrecarga na teoria , mas que os compiladores sejam inteligentes o suficiente para que isso não importe. O exemplo b tem a vantagem de ser mais compacto e limitar o escopo da variável para onde ela é usada. Ainda assim, tendo a codificar de acordo com o exemplo a .

Edit: Estou especialmente interessado no caso Java.


Isso é importante ao escrever o código Java para a plataforma Android. O Google sugere que, para que o código crítico de tempo declare variáveis ​​incrementais fora de um loop for, como se estivesse dentro do loop for, ele o declara novamente toda vez naquele ambiente. A diferença de desempenho é muito perceptível para algoritmos caros.
AaronCarson

1
@AaronCarson você poderia fornecer link para esta sugestão pelo Google
Vitaly Zinchenko

Respostas:


256

Qual é o melhor, a ou b ?

De uma perspectiva de desempenho, você teria que medir isso. (E na minha opinião, se você pode medir a diferença, o compilador não é muito bom).

Do ponto de vista da manutenção, b é melhor. Declare e inicialize variáveis ​​no mesmo local, no escopo mais restrito possível. Não deixe um buraco entre a declaração e a inicialização e não polua os namespaces que você não precisa.


5
Em vez de Double, se ele lida com String, o caso "b" ainda é melhor?
Antoops

3
@ Antoops - sim, b é melhor por razões que não têm nada a ver com o tipo de dados da variável que está sendo declarada. Por que seria diferente para Strings?
21118 Daniel Earwicker

215

Bem, eu executei seus exemplos A e B 20 vezes cada, repetindo 100 milhões de vezes (JVM - 1.5.0)

A: tempo médio de execução: 0,074 s

B: tempo médio de execução: 0,067 seg

Para minha surpresa, B foi um pouco mais rápido. Agora, tão rápido quanto os computadores, é difícil dizer se você pode medir isso com precisão. Eu codificaria da maneira A também, mas diria que isso realmente não importa.


12
Você me derrotou: eu estava prestes a postar meus resultados para criação de perfis, fiquei mais ou menos o mesmo e, surpreendentemente, B é mais rápido, realmente teria pensado em A se eu precisasse apostar nisso.
21430 Mark Davidson

14
Não é muita surpresa - quando a variável é local para o loop, ela não precisa ser preservada após cada iteração, para que possa permanecer em um registro.

142
+1 por realmente testá-lo , não apenas uma opinião / teoria que o OP poderia ter formado.
MGOwen

3
@ GoodPerson para ser honesto, eu gostaria que isso fosse feito. Eu executei esse teste cerca de 10 vezes na minha máquina para 50.000.000 a 100.000.000 de iterações com quase um trecho de código idêntico (que eu gostaria de compartilhar com quem quiser executar estatísticas). As respostas foram divididas quase igualmente de qualquer maneira, geralmente por uma margem de 900ms (mais de 50 milhões de iterações), o que não é muito. Embora meu primeiro pensamento seja que seja "ruído", ele pode se inclinar um pouco. Esse esforço parece puramente acadêmico para mim (para a maioria das aplicações da vida real) .. Eu adoraria ver um resultado de qualquer maneira;) Alguém concorda?
javatarz

3
Mostrar resultados de testes sem documentar a configuração é inútil. Isso é especialmente verdade neste caso, onde os dois fragmentos de código produzem bytecodes idênticos, portanto, qualquer diferença medida é apenas um sinal de condições de teste insuficientes.
21917 Holger

66

Depende do idioma e do uso exato. Por exemplo, em C # 1 não fazia diferença. No C # 2, se a variável local for capturada por um método anônimo (ou expressão lambda em C # 3), poderá fazer uma diferença muito significativa.

Exemplo:

using System;
using System.Collections.Generic;

class Test
{
    static void Main()
    {
        List<Action> actions = new List<Action>();

        int outer;
        for (int i=0; i < 10; i++)
        {
            outer = i;
            int inner = i;
            actions.Add(() => Console.WriteLine("Inner={0}, Outer={1}", inner, outer));
        }

        foreach (Action action in actions)
        {
            action();
        }
    }
}

Resultado:

Inner=0, Outer=9
Inner=1, Outer=9
Inner=2, Outer=9
Inner=3, Outer=9
Inner=4, Outer=9
Inner=5, Outer=9
Inner=6, Outer=9
Inner=7, Outer=9
Inner=8, Outer=9
Inner=9, Outer=9

A diferença é que todas as ações capturam a mesma outervariável, mas cada uma tem sua própria innervariável separada .


3
no exemplo B (pergunta original), ele realmente cria uma nova variável a cada vez? o que está acontecendo aos olhos da pilha?
Royi Namir

@ Jon, foi um bug no C # 1.0? Idealmente, não deveria Outerser 9?
Nawfal 8/07

@nawfal: Eu não sei o que você quer dizer. As expressões lambda não estavam na versão 1.0 ... e a versão externa é 9. Que bug você quer dizer?
Jon Skeet

@awawfal: Meu argumento é que não havia nenhum recurso de linguagem no C # 1.0 onde você pudesse dizer a diferença entre declarar uma variável dentro de um loop e declará-la fora (supondo que ambas sejam compiladas). Isso mudou no C # 2.0. Nenhum bug.
Jon Skeet

@ JonSkeet Ah, sim, eu entendo você agora, eu ignorei completamente o fato de que você não pode fechar variáveis ​​como essa na versão 1.0, meu mal! :)
Nawfal

35

A seguir, é o que escrevi e compilei no .NET.

double r0;
for (int i = 0; i < 1000; i++) {
    r0 = i*i;
    Console.WriteLine(r0);
}

for (int j = 0; j < 1000; j++) {
    double r1 = j*j;
    Console.WriteLine(r1);
}

É isso que recebo do .NET Reflector quando o CIL é renderizado novamente no código.

for (int i = 0; i < 0x3e8; i++)
{
    double r0 = i * i;
    Console.WriteLine(r0);
}
for (int j = 0; j < 0x3e8; j++)
{
    double r1 = j * j;
    Console.WriteLine(r1);
}

Então, ambos parecem exatamente iguais após a compilação. Em idiomas gerenciados, o código é convertido em código CL / byte e, no momento da execução, é convertido em linguagem de máquina. Portanto, na linguagem de máquina, um duplo nem pode ser criado na pilha. Pode ser apenas um registro, pois o código reflete que é uma variável temporária para a WriteLinefunção. Há todo um conjunto de regras de otimização apenas para loops. Portanto, o indivíduo comum não deve se preocupar com isso, especialmente em idiomas gerenciados. Há casos em que você pode otimizar o código de gerenciamento, por exemplo, se precisar concatenar um grande número de cadeias usando just string a; a+=anotherstring[i]vsStringBuilder. Há uma diferença muito grande no desempenho entre os dois. Existem muitos casos em que o compilador não pode otimizar seu código, porque não consegue descobrir o que se pretende em um escopo maior. Mas isso pode otimizar as coisas básicas para você.


int j = 0 para (; j <0x3e8; j ++) dessa maneira declarada uma vez no tempo as duas variáveis, e não cada uma para o ciclo. 2) a atribuição é mais gorda do que todas as outras opções. 3) Portanto, a regra da melhor prática é qualquer declaração fora da iteração.
Luka

24

Este é um problema no VB.NET. O resultado do Visual Basic não reinicializará a variável neste exemplo:

For i as Integer = 1 to 100
    Dim j as Integer
    Console.WriteLine(j)
    j = i
Next

' Output: 0 1 2 3 4...

Isso imprimirá 0 na primeira vez (as variáveis ​​do Visual Basic têm valores padrão quando declaradas!), Mas icada vez depois disso.

Se você adicionar um = 0, no entanto, obtém o que pode esperar:

For i as Integer = 1 to 100
    Dim j as Integer = 0
    Console.WriteLine(j)
    j = i
Next

'Output: 0 0 0 0 0...

1
Uso o VB.NET há anos e não me deparei com isso!
ChrisA

12
Sim, é desagradável descobrir isso na prática.
Michael Haren

Aqui é uma referência sobre isso de Paul Vick: panopticoncentral.net/archive/2006/03/28/11552.aspx
ferventcoder

1
@eschneider @ferventcoder Infelizmente, o @PaulV decidiu abandonar seus posts antigos , então agora esse é um link morto.
Mark Hurd

sim, apenas recentemente deparei com isso; estava à procura de alguns documentos oficiais sobre isso ...
Eric Schneider

15

Eu fiz um teste simples:

int b;
for (int i = 0; i < 10; i++) {
    b = i;
}

vs

for (int i = 0; i < 10; i++) {
    int b = i;
}

Eu compilei esses códigos com o gcc - 5.2.0. E então eu desmontei o main () desses dois códigos e esse é o resultado:

1º:

   0x00000000004004b6 <+0>:     push   rbp
   0x00000000004004b7 <+1>:     mov    rbp,rsp
   0x00000000004004ba <+4>:     mov    DWORD PTR [rbp-0x4],0x0
   0x00000000004004c1 <+11>:    jmp    0x4004cd <main+23>
   0x00000000004004c3 <+13>:    mov    eax,DWORD PTR [rbp-0x4]
   0x00000000004004c6 <+16>:    mov    DWORD PTR [rbp-0x8],eax
   0x00000000004004c9 <+19>:    add    DWORD PTR [rbp-0x4],0x1
   0x00000000004004cd <+23>:    cmp    DWORD PTR [rbp-0x4],0x9
   0x00000000004004d1 <+27>:    jle    0x4004c3 <main+13>
   0x00000000004004d3 <+29>:    mov    eax,0x0
   0x00000000004004d8 <+34>:    pop    rbp
   0x00000000004004d9 <+35>:    ret

vs

   0x00000000004004b6 <+0>: push   rbp
   0x00000000004004b7 <+1>: mov    rbp,rsp
   0x00000000004004ba <+4>: mov    DWORD PTR [rbp-0x4],0x0
   0x00000000004004c1 <+11>:    jmp    0x4004cd <main+23>
   0x00000000004004c3 <+13>:    mov    eax,DWORD PTR [rbp-0x4]
   0x00000000004004c6 <+16>:    mov    DWORD PTR [rbp-0x8],eax
   0x00000000004004c9 <+19>:    add    DWORD PTR [rbp-0x4],0x1
   0x00000000004004cd <+23>:    cmp    DWORD PTR [rbp-0x4],0x9
   0x00000000004004d1 <+27>:    jle    0x4004c3 <main+13>
   0x00000000004004d3 <+29>:    mov    eax,0x0
   0x00000000004004d8 <+34>:    pop    rbp
   0x00000000004004d9 <+35>:    ret 

Exatamente o mesmo resultado. não é uma prova de que os dois códigos produzem a mesma coisa?


3
sim, e é legal que você tenha feito isso, mas isso volta ao que as pessoas estavam dizendo sobre a dependência de idioma / compilador. Eu me pergunto como o JIT ou o desempenho da linguagem interpretada seriam afetados.
user137717

12

É dependente da linguagem - o IIRC C # otimiza isso, portanto não há diferença, mas o JavaScript (por exemplo) fará toda a alocação de memória mostrada a cada vez.


Sim, mas isso não significa muito. Fiz um teste simples com um loop for executando 100 milhões de vezes e descobri que a maior diferença a favor de declarar fora do loop era de 8 ms. Geralmente era mais parecido com 3-4 e, ocasionalmente, declarar que fora do loop tinha pior desempenho (até 4 ms), mas isso não era típico.
user137717

11

Eu sempre usaria A (em vez de confiar no compilador) e também poderia reescrever para:

for(int i=0, double intermediateResult=0; i<1000; i++){
    intermediateResult = i;
    System.out.println(intermediateResult);
}

Isso ainda restringe intermediateResulto escopo do loop, mas não é redefinido durante cada iteração.


12
Deseja conceitualmente que a variável viva pela duração do loop em vez de separadamente por iteração? Eu raramente faço. Escreva um código que revele sua intenção o mais claramente possível, a menos que você tenha um motivo muito, muito bom para fazer o contrário.
Jon Skeet

4
Ah, bom compromisso, nunca pensei nisso! IMO, o código se torna um pouco menos visualmente 'claro' embora)
Rabarberski

2
@ Jon - Eu não tenho idéia do que o OP está realmente fazendo com o valor intermediário. Apenas pensei que era uma opção que vale a pena considerar.
Triptych

6

Na minha opinião, b é a melhor estrutura. Em a, o último valor de intermediárioResult permanece após a conclusão do loop.

Editar: Isso não faz muita diferença com os tipos de valor, mas os tipos de referência podem ser um pouco pesados. Pessoalmente, gosto que as variáveis ​​sejam desreferenciadas o mais rápido possível para a limpeza, eb faz isso por você,


sticks around after your loop is finished- embora isso não importe em uma linguagem como Python, onde os nomes vinculados permanecem até a função terminar.
precisa saber é o seguinte

@ new123456: O OP solicitou detalhes sobre Java, mesmo que a pergunta fosse feita de maneira um pouco genérica. Muitas linguagens derivadas de C têm escopo no nível de bloco: C, C ++, Perl (com a mypalavra - chave), C # e Java para o nome 5 que eu usei.
Powerlord

Eu sei - foi uma observação, não uma crítica.
new123456

5

Suspeito que alguns compiladores possam otimizar ambos para que sejam o mesmo código, mas certamente não todos. Então, eu diria que você está melhor com o primeiro. A única razão para o último é se você deseja garantir que a variável declarada seja usada apenas dentro do seu loop.


5

Como regra geral, declaro minhas variáveis ​​no escopo mais interno possível. Portanto, se você não estiver usando o intermediárioResult fora do loop, eu usaria o B.


5

Um colega de trabalho prefere a primeira forma, dizendo que é uma otimização, preferindo reutilizar uma declaração.

Prefiro o segundo (e tento convencer meu colega de trabalho! ;-)), depois de ler o seguinte:

  • Reduz o escopo das variáveis ​​para onde elas são necessárias, o que é uma coisa boa.
  • Java otimiza o suficiente para não fazer diferença significativa no desempenho. IIRC, talvez a segunda forma seja ainda mais rápida.

De qualquer forma, ele se enquadra na categoria de otimização prematura que depende da qualidade do compilador e / ou JVM.


5

Há uma diferença no C # se você estiver usando a variável em um lambda, etc. Mas, em geral, o compilador basicamente fará a mesma coisa, assumindo que a variável seja usada apenas dentro do loop.

Dado que eles são basicamente os mesmos: Observe que a versão b torna muito mais óbvio para os leitores que a variável não é e não pode ser usada após o loop. Além disso, a versão b é muito mais facilmente refatorada. É mais difícil extrair o corpo do loop em seu próprio método na versão a. Além disso, a versão b garante que não haja efeito colateral em tal refatoração.

Portanto, a versão a me irrita sem fim, porque não há benefício para ela e torna muito mais difícil argumentar sobre o código ...


5

Bem, você sempre pode fazer um escopo para isso:

{ //Or if(true) if the language doesn't support making scopes like this
    double intermediateResult;
    for (int i=0; i<1000; i++) {
        intermediateResult = i;
        System.out.println(intermediateResult);
    }
}

Dessa forma, você apenas declara a variável uma vez e ela morre quando você sai do loop.


4

Eu sempre pensei que, se você declarar suas variáveis ​​dentro do seu loop, estará perdendo memória. Se você tem algo parecido com isto:

for(;;) {
  Object o = new Object();
}

Além disso, o objeto não precisa ser criado para cada iteração, mas também deve haver uma nova referência alocada para cada objeto. Parece que se o coletor de lixo estiver lento, você terá várias referências pendentes que precisam ser limpas.

No entanto, se você tiver este:

Object o;
for(;;) {
  o = new Object();
}

Então você está apenas criando uma única referência e atribuindo um novo objeto a cada vez. Claro, pode demorar um pouco mais para ficar fora do escopo, mas só há uma referência pendente para lidar.


3
Uma nova referência não é alocada para cada objeto, mesmo que a referência seja declarada no loop 'for'. Nos dois casos: 1) 'o' é uma variável local e o espaço de pilha é alocado uma vez para ela no início da função. 2) Há um novo objeto criado em cada iteração. Portanto, não há diferença no desempenho. Para organização do código, legibilidade e manutenção, é melhor declarar a referência dentro do loop.
Ajoy Bhatia

1
Embora eu não possa falar em Java, no .NET a referência não é 'alocada' para cada objeto no primeiro exemplo. Há uma única entrada na pilha para essa variável local (para o método). Para seus exemplos, o IL criado é idêntico.
Jesse C. Slicer

3

Eu acho que depende do compilador e é difícil dar uma resposta geral.


3

Minha prática é a seguinte:

  • se o tipo de variável for simples (int, double, ...) , prefiro a variante b (interna).
    Razão: reduzindo o escopo da variável.

  • se o tipo de variável não for simples (algum tipo de classou struct) , prefiro a variante a (fora).
    Razão: redução do número de chamadas de ctor-dtor.


1

Do ponto de vista do desempenho, o exterior é (muito) melhor.

public static void outside() {
    double intermediateResult;
    for(int i=0; i < Integer.MAX_VALUE; i++){
        intermediateResult = i;
    }
}

public static void inside() {
    for(int i=0; i < Integer.MAX_VALUE; i++){
        double intermediateResult = i;
    }
}

Eu executei as duas funções 1 bilhão de vezes cada. outside () levou 65 milissegundos. inside () levou 1,5 segundos.


2
Deve ter sido Depurar compilação não otimizada, não é?
Tomasz Przychodzki 12/02

int j = 0 para (; j <0x3e8; j ++) dessa maneira declarada uma vez no tempo as duas variáveis, e não cada uma para o ciclo. 2) a atribuição é mais gorda do que todas as outras opções. 3) Portanto, a regra da melhor prática é qualquer declaração fora da iteração.
Luka

1

Testei para JS com o nó 4.0.0, se alguém estiver interessado. Declarar fora do loop resultou em uma melhoria de desempenho de ~ 0,5 ms, em média, mais de 1000 tentativas com 100 milhões de iterações de loop por tentativa. Então eu vou dizer: vá em frente e escreva da maneira mais legível / sustentável que é B, imo. Eu colocaria meu código em um violino, mas usei o módulo Nó com desempenho agora. Aqui está o código:

var now = require("../node_modules/performance-now")

// declare vars inside loop
function varInside(){
    for(var i = 0; i < 100000000; i++){
        var temp = i;
        var temp2 = i + 1;
        var temp3 = i + 2;
    }
}

// declare vars outside loop
function varOutside(){
    var temp;
    var temp2;
    var temp3;
    for(var i = 0; i < 100000000; i++){
        temp = i
        temp2 = i + 1
        temp3 = i + 2
    }
}

// for computing average execution times
var insideAvg = 0;
var outsideAvg = 0;

// run varInside a million times and average execution times
for(var i = 0; i < 1000; i++){
    var start = now()
    varInside()
    var end = now()
    insideAvg = (insideAvg + (end-start)) / 2
}

// run varOutside a million times and average execution times
for(var i = 0; i < 1000; i++){
    var start = now()
    varOutside()
    var end = now()
    outsideAvg = (outsideAvg + (end-start)) / 2
}

console.log('declared inside loop', insideAvg)
console.log('declared outside loop', outsideAvg)

0

A) é uma aposta segura que B) ......... Imagine se você está inicializando a estrutura em loop em vez de 'int' ou 'float', e daí?

gostar

typedef struct loop_example{

JXTZ hi; // where JXTZ could be another type...say closed source lib 
         // you include in Makefile

}loop_example_struct;

//then....

int j = 0; // declare here or face c99 error if in loop - depends on compiler setting

for ( ;j++; )
{
   loop_example loop_object; // guess the result in memory heap?
}

Você certamente enfrentará problemas com vazamentos de memória !. Portanto, acredito que 'A' é uma aposta mais segura, enquanto 'B' é vulnerável à acumulação de memória, trabalhando em bibliotecas de código-fonte próximo.


0

É uma pergunta interessante. Da minha experiência, há uma pergunta definitiva a ser considerada quando você debate esse assunto por um código:

Existe alguma razão para a variável precisar ser global?

Faz sentido declarar a variável apenas uma vez, globalmente, e não muitas vezes localmente, porque é melhor para organizar o código e requer menos linhas de código. No entanto, se ele apenas precisar ser declarado localmente em um método, eu o inicializaria nesse método para que fique claro que a variável é exclusivamente relevante para esse método. Cuidado para não chamar essa variável fora do método em que ela é inicializada se você escolher a última opção - seu código não saberá do que está falando e relatará um erro.

Além disso, como uma observação lateral, não duplique nomes de variáveis ​​locais entre métodos diferentes, mesmo que seus propósitos sejam quase idênticos; isso só fica confuso.


1
lol eu discordo por muitos motivos ... No entanto, nenhum voto para baixo ... Eu respeito o seu direito de escolher
Grantly

0

esta é a melhor forma

double intermediateResult;
int i = byte.MinValue;

for(; i < 1000; i++)
{
intermediateResult = i;
System.out.println(intermediateResult);
}

1) desta maneira declarada uma vez ambas as variáveis, e não cada uma para o ciclo. 2) a tarefa é mais eficaz do que todas as outras opções. 3) Portanto, a regra da melhor prática é qualquer declaração fora da iteração.


0

Tentei a mesma coisa no Go e comparou a saída do compilador usando o go tool compile -Sgo 1.9.4

Diferença zero, conforme a saída do montador.


0

Eu tive essa mesma pergunta por um longo tempo. Então eu testei um pedaço de código ainda mais simples.

Conclusão: Para esses casos , NÃO há diferença de desempenho.

Caso de loop externo

int intermediateResult;
for(int i=0; i < 1000; i++){
    intermediateResult = i+2;
    System.out.println(intermediateResult);
}

Caso interno do laço

for(int i=0; i < 1000; i++){
    int intermediateResult = i+2;
    System.out.println(intermediateResult);
}

Eu verifiquei o arquivo compilado no descompilador do IntelliJ e, nos dois casos, obtive o mesmo Test.class

for(int i = 0; i < 1000; ++i) {
    int intermediateResult = i + 2;
    System.out.println(intermediateResult);
}

Também desmontei o código para ambos os casos, usando o método fornecido nesta resposta . Vou mostrar apenas as partes relevantes para a resposta

Caso de loop externo

Code:
  stack=2, locals=3, args_size=1
     0: iconst_0
     1: istore_2
     2: iload_2
     3: sipush        1000
     6: if_icmpge     26
     9: iload_2
    10: iconst_2
    11: iadd
    12: istore_1
    13: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
    16: iload_1
    17: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V
    20: iinc          2, 1
    23: goto          2
    26: return
LocalVariableTable:
        Start  Length  Slot  Name   Signature
           13      13     1 intermediateResult   I
            2      24     2     i   I
            0      27     0  args   [Ljava/lang/String;

Caso interno do laço

Code:
      stack=2, locals=3, args_size=1
         0: iconst_0
         1: istore_1
         2: iload_1
         3: sipush        1000
         6: if_icmpge     26
         9: iload_1
        10: iconst_2
        11: iadd
        12: istore_2
        13: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
        16: iload_2
        17: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V
        20: iinc          1, 1
        23: goto          2
        26: return
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
           13       7     2 intermediateResult   I
            2      24     1     i   I
            0      27     0  args   [Ljava/lang/String;

Se você prestar atenção, apenas o Slotdesignado para ie intermediateResultem LocalVariableTableé trocado como um produto da sua ordem de aparecimento. A mesma diferença no slot é refletida em outras linhas de código.

  • Nenhuma operação extra está sendo executada
  • intermediateResult ainda é uma variável local nos dois casos, portanto não há diferença no tempo de acesso.

BÔNUS

Os compiladores fazem uma tonelada de otimização, dê uma olhada no que acontece neste caso.

Zero caso de trabalho

for(int i=0; i < 1000; i++){
    int intermediateResult = i;
    System.out.println(intermediateResult);
}

Zero trabalho descompilado

for(int i = 0; i < 1000; ++i) {
    System.out.println(i);
}

-1

Mesmo que eu saiba que meu compilador é inteligente o suficiente, não gostarei de confiar nele e usarei a variante a).

A variante b) só faz sentido para mim se você precisar desesperadamente tornar o resultado intermediário indisponível após o corpo do loop. Mas não consigo imaginar uma situação tão desesperadora ...

EDIT: Jon Skeet fez um argumento muito bom, mostrando que a declaração variável dentro de um loop pode fazer uma diferença semântica real.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.