java - sirve - estructura for en programacion
¿Por qué es necesaria la declaración de la variable dentro de un bucle for-each en java? (4)
La forma usual de cada bucle es esta:
for(Foo bar: bars){
bar.doThings();
}
Pero si quiero mantener la barra hasta después del bucle, no puedo usar el para cada bucle:
Foo bar = null;
// - Syntax error on token "bar", Identifier expected after this token
for(bar: bars){
if(bar.condition())
break;
}
bar.doThings();
El bucle for obtiene el error de sintaxis mencionado anteriormente.
¿Por qué es esto? No me interesan las soluciones alternativas, sino la curiosidad por las consideraciones detrás de esta limitación.
En contraste, con un bucle for ordinario, la variable se puede declarar fuera o no ...
int i = 1;
for(;i<max;i++){
for(;;){
// Do things
}
}
El propósito de esta nueva sintaxis es para el embellecimiento, ya que realmente no agrega nada nuevo a Java. Supongo que no permitieron la sintaxis que hiciste por la única razón: ¡ No es hermoso! :)
Esta es una buena pregunta y me encantaría ver una respuesta en profundidad. Sin embargo, la documentación oficial dice:
Estas deficiencias fueron conocidas por los diseñadores, quienes tomaron la decisión consciente de ir con una construcción simple y limpia que cubriría la gran mayoría de los casos.
La gran mayoría de los casos es la respuesta para mí.
En una nota al margen, personalmente, creo que el bucle foreach
en Java es solo una buena sintaxis para un bucle de iterador estándar. Entonces, el compilador crea el iterador para la estructura y usa la variable para obtener el valor para la iteración actual. Para asegurarse de que la variable se haya inicializado, debe declararla para el ámbito del bucle (y creo que esto evita que la variable se use en otro lugar, por ejemplo, en otro hilo). Debido a eso, no puede utilizar la variable después del bucle. Pero, esto es solo mi opinión y me encantaría saber de alguien que lo conozca mejor. :)
Editar Aquí hay un interesante artículo sobre bucles foreach
en Java.
Otra edición que analicé (con jclasslib el jclasslib de estos métodos:
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);
}
}
Ambos métodos están representados por el mismo código de bytes:
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 diferencia está en la línea 1, el último método utiliza invokevirtual #8
. Sin embargo, ambas invocaciones dan como resultado el mismo método de Iterator
. Entonces, parece que foreach
no es más que un azúcar sintáctico que el compilador simplemente se traduce en una construcción predefinida, tal como lo dice la documentación. Esto no responde a la pregunta de por qué es así . Pienso que esto es simplemente interesante y podría valer la pena saberlo, en el contexto de la discusión.
La forma de iterar sobre una lista en este caso es:
Foo bar = null;
for(Iterator<Foo> barIterator = bars.iterator(); barIterator.hasNext();){
bar = barIterator.next(); // or whatever else you want to do
...
}
¡No itere sobre una lista usando el índice a menos que la lista implemente RandomAccess!
El bucle for mejorado es solo azúcar sintáctica para este enfoque de iterador, que mantiene la variable (aquí barra) local al bucle. (Mantener las variables lo más local posible es algo bueno, generalmente).
Supongo que solo querían promover "buenas prácticas": de la guía de lenguaje Java:
Estas deficiencias fueron conocidas por los diseñadores, quienes tomaron la decisión consciente de ir con una construcción simple y limpia que cubriría la gran mayoría de los casos.
Como sabemos, el comportamiento que está solicitando puede simularse simplemente expandiendo el bucle for-each al estilo antiguo basado en iteradores, y probablemente pensaron que era lo suficientemente bueno.