Cela fait-il une différence si je déclare des variables à l'intérieur ou à l'extérieur d'une boucle en Java? [fermé]

13

Duplicata possible:
où déclarez-vous les variables? Le sommet d'une méthode ou quand vous en avez besoin?

Cela fait-il une différence si je déclare des variables à l'intérieur ou à l'extérieur d'une boucle en Java?

Est-ce

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

égal à cela (en ce qui concerne l'utilisation de la mémoire)?

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

Et si la variable temporaire est par exemple une ArrayList?

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

EDIT: avec javap -cj'ai obtenu la sortie suivante

Variable en dehors de la boucle:

  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  

Variable à l'intérieur de la boucle:

  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        

Et pour les intéressés, ce code:

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++;
    }
}

produit ceci:

  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   

Mais l'optimisation se produit alors lors de l'exécution. Existe-t-il un moyen de regarder le code optimisé? (Désolé pour la longue modification)

Puckl
la source
1
Je suis heureux que vous ayez réellement regardé le démontage et j'espère qu'il vous a appris quelque chose. J'avais espéré que quelqu'un ayant une réelle expérience Java répondrait à votre dernière question sur le code optimisé, mais vous pouvez peut-être poster cette partie spécifique sur Stackoverflow - cela semble être une question très concrète.
Joris Timmermans
Oui, je vais essayer d'obtenir le code optimisé. (La question a un peu changé, j'ai posé la question avec le code optimisé dans l'édition)
Puckl
Lien brisé sur Duplicate. Il est temps de faire de cette question un original.
Zon

Réponses:

4

La réponse commune à la plupart de ces questions devrait être "pourquoi ne pas l'essayer et le découvrir?". En Java, vous pourriez probablement jeter un œil au bytecode généré (je crois que l'outil s'appelle javap), pour voir quelle est la différence de code d'octet entre ces deux façons de déclarer la variable.

Le faire comme ça est une meilleure expérience d'apprentissage pour vous, car la prochaine fois que vous rencontrez un problème d'optimisation, vous pouvez utiliser le même outil pour vérifier que le compilateur fait ce que vous attendez - cela vous aidera à éviter de changer inutilement votre codage le style lorsque l'optimiseur fonctionne bien tout seul, ou trouver de réels ajustements lorsque vous avez vraiment besoin de ce dernier bit de performance.

Joris Timmermans
la source
3

Réponse courte: non. Il y avait déjà des questions similaires quelque part sur ce site. Il n'y a pas de différence notable selon le bytecode généré. Les déclarer en cas de besoin produit moins de lignes de code

Voici la réponse acceptée: /software//a/56590/43451

Kemoda
la source
Qu'en est-il des performances lorsque vous créez un nouvel objet à l'intérieur de la boucle, qui pourrait tout aussi bien être créé une seule fois?
Bubblewrap
3
Dans ce cas, il y a évidemment des pertes de performances et de mémoire. Mais ce n'est pas tout à fait le cas dans la question de l'op
Kemoda
1
Le lien est rompu.
Zon
1

Au niveau de la variable individuelle, il n'y a pas de différence d'efficacité significative, mais si vous aviez une fonction avec 1000 boucles et 1000 variables (sans parler du mauvais style impliqué), il pourrait y avoir des différences systémiques car toutes les vies de toutes les variables seraient même au lieu de se chevaucher. Cela pourrait affecter des choses comme la taille de la pile et la capacité du garbage collector à nettoyer les variables qui étaient maintenues en vie plus longtemps que nécessaire.

En outre, il est préférable de donner aux variables la plus petite portée possible. Il prévient les accidents.

ddyer
la source
Ce n'est pas vrai - au niveau de la JVM, il n'y a pas de portée limitée pour les variables locales.
Michael Borgwardt
voulez-vous dire que si j'écris pour (int i = ..) 1000 fois, il y aura 1000 variables différentes sur la pile lorsque je quitterai la fonction?
ddyer
selon artima.com/insidejvm/ed2/jvm8.html "Par exemple, si deux variables locales ont des portées limitées qui ne se chevauchent pas, telles que les variables locales i et j dans Example3b, les compilateurs sont libres d'utiliser la même entrée de tableau pour les deux variables. "Et cela n'a de sens que les compilateurs sont libres d'optimiser la taille du cadre de pile de cette façon.
ddyer
1
Bon point; mais si nous parlons d'optimisations du compilateur, le compilateur peut presque aussi facilement réutiliser les entrées de variables locales pour les variables qui ont une portée lexicale qui se chevauchent mais ne sont pas utilisées de manière chevauchante.
Michael Borgwardt