Fa differenza se dichiaro variabili all'interno o all'esterno di un ciclo in Java? [chiuso]


13

Possibile duplicato:
dove dichiarate le variabili? Il top di un metodo o quando ne hai bisogno?

Fa differenza se dichiaro variabili all'interno o all'esterno di un ciclo in Java?

È questo

for(int i = 0; i < 1000; i++) {
   int temp = doSomething();
   someMethod(temp);
}

uguale a questo (rispetto all'utilizzo della memoria)?

int temp = 0;
for(int i = 0; i < 1000; i++) {
   temp = doSomething();
   someMethod(temp);
}

E se la variabile temporanea fosse ad esempio una ArrayList?

for(int i = 0; i < 1000; i++) {
   ArrayList<Integer> array = new ArrayList<Integer>();
   fillArray(array);
   // do something with the array
}

EDIT: con javap -cho ottenuto il seguente output

Variabile al di fuori del ciclo:

  public static void main(java.lang.String[]);
    Code:
       0: iconst_0      
       1: istore_1      
       2: iconst_0      
       3: istore_2      
       4: iload_2       
       5: sipush        1000
       8: if_icmpge     25
      11: invokestatic  #2                  // Method doSomething:()I
      14: istore_1      
      15: iload_1       
      16: invokestatic  #3                  // Method someMethod:(I)V
      19: iinc          2, 1
      22: goto          4
      25: return  

Variabile all'interno del ciclo:

  public static void main(java.lang.String[]);
    Code:
       0: iconst_0      
       1: istore_1      
       2: iload_1       
       3: sipush        1000
       6: if_icmpge     23
       9: invokestatic  #2                  // Method doSomething:()I
      12: istore_2      
      13: iload_2       
      14: invokestatic  #3                  // Method someMethod:(I)V
      17: iinc          1, 1
      20: goto          2
      23: return        

E per gli interessati, questo codice:

public class Test3 {
    public static void main(String[] args) {
        for(int i = 0; i< 1000; i++) {
            someMethod(doSomething());
        }   
    }
    private static int doSomething() {
        return 1;
    }
    private static void someMethod(int temp) {
        temp++;
    }
}

produce questo:

  public static void main(java.lang.String[]);
    Code:
       0: iconst_0      
       1: istore_1      
       2: iload_1       
       3: sipush        1000
       6: if_icmpge     21
       9: invokestatic  #2                  // Method doSomething:()I
      12: invokestatic  #3                  // Method someMethod:(I)V
      15: iinc          1, 1
      18: goto          2
      21: return   

Ma l'ottimizzazione avviene in fase di esecuzione allora. C'è un modo per guardare il codice ottimizzato? (Ci scusiamo per il lungo EDIT)


1
Sono contento che tu abbia effettivamente visto lo smontaggio e spero che ti abbia insegnato qualcosa. Speravo che qualcuno con esperienza Java effettiva avrebbe risposto alla tua ultima domanda sul codice ottimizzato, ma forse puoi pubblicare quella parte specifica su Stackoverflow - sembra essere una domanda molto concreta.
Joris Timmermans,

Sì, proverò a ottenere il codice ottimizzato. (La domanda è cambiata un po ', ho posto la cosa con il codice ottimizzato nella modifica)
Puckl

Collegamento interrotto su duplicato. È tempo di rendere questa domanda un originale.
Zon,

Risposte:


4

La risposta comune alla maggior parte di queste domande dovrebbe essere "perché non provarla e scoprirla?". In Java potresti probabilmente dare un'occhiata al bytecode generato (credo che lo strumento si chiami javap), per vedere quale sia la differenza nel codice byte tra quei due modi di dichiarare la variabile.

Farlo in questo modo è un'esperienza di apprendimento migliore per te, perché la prossima volta che riscontri un problema di ottimizzazione puoi utilizzare lo stesso strumento per verificare che il compilatore stia facendo quello che ti aspetti - ti aiuterà a evitare di modificare inutilmente la tua codifica stile quando l'ottimizzatore funziona bene da solo o trova modifiche effettive quando hai davvero bisogno dell'ultimo bit di prestazioni.


3

Risposta breve: no. C'erano già domande simili da qualche parte su questo sito. Non vi è alcuna differenza notevole secondo il bytecode generato. Dichiararli quando necessario produce meno righe di codice

Ecco la risposta accettata: /software//a/56590/43451


Che dire delle prestazioni quando si crea un nuovo oggetto all'interno del ciclo, che potrebbe anche essere creato una sola volta?
Bubblewrap

3
In questo caso ovviamente c'è una penalità per prestazioni e memoria. Ma non è proprio il caso della domanda
dell'op

1
Il collegamento è interrotto.
Zon,

1

A livello della singola variabile non c'è una differenza significativa nell'efficacia, ma se si avesse una funzione con 1000 loop e 1000 variabili (non importa lo stile cattivo implicito) ci potrebbero essere differenze sistemiche perché tutte le vite di tutte le variabili sarebbero lo stesso invece che sovrapposto. Ciò potrebbe influire su aspetti quali le dimensioni dello stack e la capacità del garbage collector di ripulire le variabili che venivano mantenute in vita più a lungo del necessario.

Inoltre, è molto meglio dare alle variabili il più piccolo ambito possibile. Previene gli incidenti.


Questo non è vero: a livello di JVM non esiste un ambito limitato per le variabili locali.
Michael Borgwardt,

vuoi dire che se scrivo per (int i = ..) 1000 volte, ci saranno 1000 diverse variabili nello stack quando esco dalla funzione?
oscuro

secondo artima.com/insidejvm/ed2/jvm8.html "Ad esempio, se due variabili locali hanno ambiti limitati che non si sovrappongono, come le variabili locali iej in Esempio3b, i compilatori sono liberi di usare la stessa voce di array per entrambe le variabili ". E questo ha senso solo, i compilatori sono liberi di ottimizzare le dimensioni del frame dello stack in questo modo.
tinto

1
Buon punto; ma se stiamo parlando di ottimizzazioni del compilatore, il compilatore può riutilizzare quasi altrettanto facilmente le voci delle variabili locali per le variabili che hanno un ambito lessicale sovrapposto ma non sono utilizzate in modo sovrapposto.
Michael Borgwardt,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.