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

La forme habituelle du pour chaque boucle est la suivante:

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

Mais si je veux conserver la barre jusqu’à la fin de la boucle, je ne peux pas utiliser le pour chaque boucle:

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

La boucle for obtient l’erreur de syntaxe mentionnée ci-dessus.

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

En revanche, avec une boucle ordinaire, la variable peut être déclarée à l’extérieur ou pas du tout …

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

C’est une bonne question et je serais heureux de voir une réponse approfondie. Cependant, la documentation officielle dit:

Ces conceptions étaient connues des concepteurs, qui ont pris la décision consciente de choisir une construction simple et propre qui couvrirait la grande majorité des cas.

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

En passant, personnellement, je pense que la boucle foreach en Java est juste une belle syntaxe pour une boucle d’iterator standard. Ainsi, le compilateur crée l’iterator de la structure et utilise la variable pour obtenir la valeur de l’itération en cours. Pour vous assurer que la variable a été initialisée, vous devez la déclarer pour la scope de la boucle (et je pense que cela empêche l’utilisation de la variable ailleurs, par exemple dans un autre thread). Pour cette raison, vous ne pouvez pas utiliser la variable après la boucle. Mais, ce n’est que mon avis et je serais très heureux d’entendre quelqu’un qui le connaît mieux. 🙂

Edit Voici un article intéressant sur les boucles foreach en Java.

Un autre assembly que j’ai analysé (avec jclasslib le bytecode de ces méthodes:

  private static void testForEach(ArrayList als) { for(Ssortingng s: als) System.out.println(s); } private static void testIterator(ArrayList als) { for(Iterator is = als.iterator(); is.hasNext();) { Ssortingng 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  4 astore_1 5 aload_1 6 invokeinterface #3  count 1 11 ifeq 34 (+23) 14 aload_1 15 invokeinterface #4  count 1 20 checkcast #5  23 astore_2 24 getstatic #6  27 aload_2 28 invokevirtual #7  31 goto 5 (-26) 34 return 

La différence est à la ligne 1, la dernière méthode utilise invokevirtual #8 . Cependant, les deux invocations entraînent l’appel de la même méthode d’ Iterator . Il semble donc que foreach n’est rien de plus qu’un sucre syntaxique que le compilateur ne traduit que dans une construction prédéfinie, comme le dit la documentation. Cela ne répond pas à la question de savoir pourquoi c’est comme ça . Je pense que c’est juste intéressant et pourrait être intéressant de le savoir, dans le contexte de la discussion.

Je suppose qu’ils ont juste voulu promouvoir les “bonnes pratiques”: du guide de langage Java:

Ces conceptions étaient connues des concepteurs, qui ont pris la décision consciente de choisir une construction simple et propre qui couvrirait la grande majorité des cas.

Comme nous le soaps, le comportement que vous demandez peut être simulé en étendant simplement la boucle for-each à l’ancien style basé sur un iterator, et ils ont probablement pensé que c’était tout simplement bon.

La manière de parcourir une liste dans ce cas est la suivante:

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

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

La boucle améliorée est simplement du sucre syntaxique pour cette approche itérative, qui conserve la variable (ici la barre) locale à la boucle. (Garder des variables aussi locales que possible est une bonne chose en général.)

Le but de cette nouvelle syntaxe est d’embellir, car elle n’ajoute rien de nouveau à Java. Je suppose qu’ils n’ont pas permis la syntaxe que vous avez faite pour la seule raison: ce n’est pas beau! 🙂