52 votes

Pourquoi la déclaration de la variable est-elle requise dans une boucle for-each en java?

La forme habituelle de la de la pour chaque boucle est ceci:

for(Foo bar: bars){
    bar.doThings();
}

Mais si je veux garder la barre jusqu'à ce que après la boucle, je peux pas utiliser la boucle for each:

Foo bar = null;
// - Syntax error on token "bar", Identifier expected after this token
for(bar: bars){ 
    if(bar.condition())
        break;
}
bar.doThings();

Pour la boucle obtient l'erreur de syntaxe mentionnés ci-dessus.

Pourquoi est-ce? Je ne suis pas intéressé par des solutions de contournement, mais juste curieux de considérations derrière cette limitation.

En revanche, avec un ordinaire de la boucle, la variable peut être déclarée à l'extérieur ou pas du tout...

int i = 1;
for(;i<max;i++){
    for(;;){
        // Do things
    }
}

29voto

Sorrow Points 4176

C'est une bonne question et je serais heureux de voir que certains en profondeur de la réponse. Toutefois, la documentation officielle dit:

Ces lacunes ont été connues par le les concepteurs, qui ont délibérément la décision d'aller avec un chiffon propre, simple construire qui engloberait le grand la majorité des cas.

La grande majorité des cas, est la réponse pour moi.

Sur une note de côté, personnellement, je pense qu' foreach boucle en Java est juste une belle syntaxe pour un itérateur boucle. Ainsi, le compilateur crée un itérateur pour la structure et utilise la variable d'obtenir la valeur pour l'itération en cours. Pour s'assurer que la variable a été initialisée, vous devez le déclarer à la portée de boucle (et je pense que cela empêche la variable d'être utilisé de quelque part d'autre, par exemple dans un autre thread). À cause de cela, vous ne pouvez pas utiliser la variable après la boucle. Mais, c'est juste mon avis et je serais très heureux d'entendre quelqu'un qui la connaît mieux. :)

Edit Voici un article intéressant à propos de foreach boucles en Java.

Un autre edit j'ai analysé (avec jclasslib le pseudo-code de ces méthodes:

 private static void testForEach(ArrayList<String> als) {
  for(String s: als)
    System.out.println(s);
 }

 private static void testIterator(ArrayList<String> als) {
  for(Iterator<String> is = als.iterator(); is.hasNext();) {
   String s = is.next();
   System.out.println(s);
  } 
 }

Les deux méthodes sont représentées par le même bytecode:

 0 aload_0
 1 invokevirtual #2 <java/util/ArrayList.iterator>
 4 astore_1
 5 aload_1
 6 invokeinterface #3 <java/util/Iterator.hasNext> count 1
11 ifeq 34 (+23)
14 aload_1
15 invokeinterface #4 <java/util/Iterator.next> count 1
20 checkcast #5 <java/lang/String>
23 astore_2
24 getstatic #6 <java/lang/System.out>
27 aload_2
28 invokevirtual #7 <java/io/PrintStream.println>
31 goto 5 (-26)
34 return

La différence est dans la ligne 1, la dernière méthode utilise invokevirtual #8. Cependant, les deux appels suite à l'appel à la même méthode de Iterator. Donc, il semble que foreach n'est rien de plus qu'un sucre syntaxique que le compilateur juste se traduit par un prédéfini construire, comme dit la documentation. Cela ne répond pas à la question pourquoi c'est la façon dont il est. J'ai si c'est juste intéressant et pourrait être intéressant de savoir, dans le contexte de la discussion.

4voto

Waldheinz Points 6308

Je suppose qu'ils ont juste voulu promouvoir les "bonnes pratiques": à partir de la Java de la langue guide:

Ces lacunes ont été connus par les concepteurs, qui a pris la décision consciente d'aller avec un chiffon propre, construction simple qui permettrait de couvrir la grande majorité des cas.

Comme nous le savons, le comportement que vous demandez peut être simulé par juste élargissement de la boucle for-each de l'ancien itérateur basée sur le style, et probablement ils ont juste pensé que son Assez Bon.

3voto

Puce Points 13540

Le moyen de parcourir une liste dans ce cas est:

 Foo bar = null;
for(Iterator<Foo> barIterator = bars.iterator(); barIterator.hasNext();){ 
   bar = barIterator.next(); // or whatever else you want to do
   ...
}
 

Ne parcourez pas une liste à l'aide de l'index, sauf si la liste implémente RandomAccess!

La boucle for améliorée est simplement un sucre syntaxique pour cette approche itérateur, qui garde la variable (ici barre) locale à la boucle. (Généralement, garder les variables aussi locales que possible est une bonne chose.)

1voto

Manny Points 3335

Le but de cette nouvelle syntaxe est d’embellir car elle n’ajoute rien de nouveau à Java. J'imagine qu'ils n'autorisaient pas la syntaxe que vous aviez utilisée pour l'unique raison: ce n'est pas beau! :)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X