java - rapidos - como hacer rizos sin calor
Mejorado para compilación de bucles bien para JDK 8 pero no 7 (6)
Considere el siguiente fragmento de código, lo aproveché después de algunas refactorizaciones, cuando compruebo por qué el servidor de compilación informó una compilación rota pero estaba bien en mi IDE:
List<String> text;
...
for (String text : text) {...}
Por lo tanto, el mismo nombre se utiliza para la cadena y la lista dentro de la para cada uno.
Por supuesto, esto no es muy inteligente, pero después de seguir mi curiosidad antes de cambiarle el nombre, vi que el código anterior compila bien con JDK 8, pero da el siguiente error con JDK 7:
error: for-each not applicable to expression type
for (String text : text) {
^
required: array or java.lang.Iterable
found: String
1 error
Sé que se hicieron cambios en varias partes en esta área dentro del JDK, pero ¿alguien me puede aclarar por qué exactamente ocurre este comportamiento?
Actualización: desde que recibí algunos comentarios sobre el comportamiento diferente, aquí hay una clase de muestra completa:
import java.util.Arrays;
import java.util.List;
public class Strange {
List<String> text = Arrays.asList("Max", "Alex", "Maria");
public static void main(String[] args) {
new Strange().doSomething("Alex");
}
public void doSomething(String name) {
for (String text : text) {
System.out.println(text.equals("Alex"));
}
}
}
Y aquí está el proceso de compilación y salida (Windows 7 64bit):
C:/copy>c:/Projects/java/jdk1.7.0_79/bin/javac.exe Strange.java
Strange.java:13: error: for-each not applicable to expression type
for (String text : text) {
^
required: array or java.lang.Iterable
found: String
1 error
C:/copy>c:/Projects/java/jdk1.8.0_60/bin/javac.exe Strange.java
C:/copy>
Conclusión: estaba tan desconcertado por qué mi IDE (que usa 8) no se quejó con el doble del mismo nombre en una declaración, pero ahora está claro que no es una afirmación. Realmente me pregunto por qué este punto ha estado vigente desde hace tanto tiempo si el JLS indica lo contrario. Pero de todos modos, gracias por las ideas que he recibido y las excelentes respuestas (que me dificultaron elegir la mejor).
Aunque creo que las otras respuestas son correctas, permítanme ser el abogado del diablo y ofrecer la opinión contraria.
Obviamente JDK 7 analiza el bucle foreach de tal manera que la variable ''texto'' también está en el alcance después de '':''. Para probar esto, escribí el siguiente método. Se compila y funciona perfectamente en Java 1.7:
public static void main(String[] args) {
for (String text : new String[] {text = "hello", text, text, text})
System.out.println(text);
}
Aunque otros han dicho que esto es un error en jdk 1.7 (y probablemente lo es), no pude encontrar ningún lugar en el JLS que diga específicamente que la variable que acaba de declararse no está en el alcance después del '':''. Si no es un error, entonces Java 8 rompe la compatibilidad.
Diría que es un error del compilador en la versión particular del compilador de Java 7 que está utilizando.
El text
anterior es un campo, y es legal que el text
local declarado en la sentencia for
muestre un campo.
Luego miramos lo que significa el ciclo for. De acuerdo con el JLS,
for (String text : text) {...}
es equivalente a
for (Iterator<String> #i = text.iterator(); #i.hasNext(); ) {
String text = (String) #i.next();
...
}
Como puede ver, el text
interno no está dentro del alcance de la expresión text.iterator()
.
Intenté buscar en Oracle Java Bugs Database, pero no encontré nada que coincidiera con este escenario.
Esto compiló bien para mí. Estoy usando Java 8 JDK, en Netbeans, en una máquina de 64 bits (Windows 7).
Creo que este es un problema de localización relacionado con su IDE o compilador. Usé tu ejemplo exacto, siendo el resultado
false
true
false
Hubo una advertencia, indicando que es posible, pero no se recomienda ocultar un campo con una variable local.
Esto debería compilarse bien para JDK 7 y 8.
Citando JLS §14.14.2 (que es el mismo para la especificación de Java 7):
El enunciado mejorado para es equivalente a una declaración básica para el formulario:
for (I #i = Expression.iterator(); #i.hasNext(); ) { {VariableModifier} TargetType Identifier = (TargetType) #i.next(); Statement }
Reescribiendo el bucle forzado con Iterator
for (String text : text) {...}
se convierte
for (Iterator<String> it = text.iterator(); it.hasNext(); ) {
String text = it.next();
}
Luego, citando el ejemplo 6.4.1 del JLS:
Una restricción similar sobre el sombreado de los miembros por las variables locales se consideró poco práctica, porque la adición de un miembro en una superclase podría hacer que las subclases tengan que cambiar el nombre de las variables locales. Las consideraciones relacionadas también hacen poco atractivas las restricciones al sombreado de las variables locales por parte de los miembros de las clases anidadas, o al sombreado de las variables locales por las variables locales declaradas dentro de las clases anidadas.
Como tal, no hay error de tiempo de compilación aquí porque no se realiza ninguna restricción al sombrear una variable miembro por una variable local, que es el caso aquí: la variable local String text
está sombreando la variable miembro List<String> text
.
Si bien el razonamiento, utilizando la traducción especificada del bucle for
mejorado for
bucle for
tradicional, utilizado por other answers es correcto, hay una especificación explícita sobre los ámbitos:
§6.3. Alcance de una declaración
...
El alcance de una variable local declarada en la parte FormalParameter de una instrucción
for
§14.14.2 ( §14.14.2 ) es la §14.14.2 contenida.
( enlace directo )
Por lo tanto, el alcance de la variable no incluye la expresión del bucle mejorado for
...
Puede verificar que esto no haya cambiado, en comparación con Java 7 y Java 6 , aunque ambos (probé Java 6 javac
) exhiben el comportamiento contradictorio.
Entonces, este cambio en el comportamiento del compilador es la solución de un error anterior ...
Su servidor de compilación puede estar compilando usando un jdk diferente al de su máquina local. (No solo un número de versión diferente, sino una implementación completamente diferente). Eclipse es uno que usa su propio compilador, creo que facilita el intercambio en caliente de su código.
Utilizar el mismo nombre para la colección y el elemento debería plantear problemas en cualquier lugar , pero he oído hablar de Eclipse y de vez en cuando me di cuenta de que tolera cosas que el JDK de Sun / Oracle no.