[Java] Déclarer des variables à l'intérieur ou à l'extérieur d'une boucle



Answers

J'ai comparé le code octet de ces deux exemples (similaires):

Regardons 1. exemple :

package inside;

public class Test {
    public static void main(String[] args) {
        while(true){
            String str = String.valueOf(System.currentTimeMillis());
            System.out.println(str);
        }
    }
}

après javac Test.java , javap -c Test vous obtiendrez:

public class inside.Test extends java.lang.Object{
public inside.Test();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

public static void main(java.lang.String[]);
  Code:
   0:   invokestatic    #2; //Method java/lang/System.currentTimeMillis:()J
   3:   invokestatic    #3; //Method java/lang/String.valueOf:(J)Ljava/lang/String;
   6:   astore_1
   7:   getstatic       #4; //Field java/lang/System.out:Ljava/io/PrintStream;
   10:  aload_1
   11:  invokevirtual   #5; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   14:  goto    0

}

Regardons 2. l'exemple :

package outside;

public class Test {
    public static void main(String[] args) {
        String str;
        while(true){
            str =  String.valueOf(System.currentTimeMillis());
            System.out.println(str);
        }
    }
}

après javac Test.java , javap -c Test vous obtiendrez:

public class outside.Test extends java.lang.Object{
public outside.Test();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

public static void main(java.lang.String[]);
  Code:
   0:   invokestatic    #2; //Method java/lang/System.currentTimeMillis:()J
   3:   invokestatic    #3; //Method java/lang/String.valueOf:(J)Ljava/lang/String;
   6:   astore_1
   7:   getstatic       #4; //Field java/lang/System.out:Ljava/io/PrintStream;
   10:  aload_1
   11:  invokevirtual   #5; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   14:  goto    0

}

Les observations montrent qu'il n'y a pas de différence entre ces deux exemples. C'est le résultat des spécifications de la JVM ...

Mais au nom de la meilleure pratique de codage, il est recommandé de déclarer la variable dans la plus petite portée possible (dans cet exemple, elle est à l'intérieur de la boucle, car c'est le seul endroit où la variable est utilisée).

Question

Pourquoi ce qui suit fonctionne-t-il bien?

String str;
while (condition) {
    str = calculateStr();
    .....
}

Mais celui-ci est dit dangereux / incorrect:

while (condition) {
    String str = calculateStr();
    .....
}

Est-il nécessaire de déclarer des variables en dehors de la boucle?




Je pense que la taille de l'objet compte aussi. Dans l'un de mes projets, nous avions déclaré et initialisé un grand tableau bidimensionnel qui faisait que l'application jetait une exception de mémoire insuffisante. Nous avons plutôt déplacé la déclaration hors de la boucle et effacé le tableau au début de chaque itération.




Vous avez un risque de NullPointerException si votre méthode calculateStr() renvoie null , puis vous essayez d'appeler une méthode sur str.

Plus généralement, évitez d'avoir des variables avec une valeur nulle . C'est plus fort pour les attributs de classe, d'ailleurs.




La déclaration de chaîne str en dehors de la boucle wile lui permet d'être référencée à l'intérieur et à l'extérieur de la boucle while. La déclaration de chaîne str à l'intérieur de la boucle while permet de la référencer uniquement dans la boucle while.




si vous voulez utiliser str dehors de looop aussi; déclarez-le dehors. Sinon, la 2ème version est correcte.




La variable str sera disponible et réservera de l'espace en mémoire même après avoir été exécuté en dessous du code.

 String str;
    while(condition){
        str = calculateStr();
        .....
    }

La variable str ne sera pas disponible et la mémoire sera libérée qui a été allouée pour la variable str dans le code ci-dessous.

while(condition){
    String str = calculateStr();
    .....
}

Si nous suivions le second, cela réduirait sûrement la mémoire de notre système et augmenterait les performances.




Selon le guide Google Android Development, la portée de la variable doit être limitée. Veuillez vérifier ce lien:

Limite variable portée




Si vous n'avez pas besoin d'utiliser la str après la boucle while (portée liée), la seconde condition

  while(condition){
        String str = calculateStr();
        .....
    }

est meilleur puisque si vous définissez un objet sur la pile seulement si la condition est vraie. C'est à dire l'utiliser si vous en avez besoin




Une solution à ce problème pourrait être de fournir une variable variable encapsulant la boucle while:

{
  // all tmp loop variables here ....
  // ....
  String str;
  while(condition){
      str = calculateStr();
      .....
  }
}

Ils seraient automatiquement dé-référence lorsque la portée externe se termine.




La déclaration à l'intérieur de la boucle limite la portée de la variable respective. Tout dépend de l'exigence du projet sur la portée de la variable.






Links