java - recibir - ¿Por qué la variable local de un bucle forzado mejorado debe ser local?
paso de parametros en java pdf (5)
Esta pregunta ya tiene una respuesta aquí:
De acuerdo con la Especificación del lenguaje Java, § 14.14.2 , la variable de un bucle for
mejorado debe ser local al bucle. En otras palabras, esto compila:
for (State state : State.values()) {
// do something for each state
}
pero esto no:
State state;
for (state: State.values()) {
// do something for each state
}
El JLS no da ningún razonamiento para esta elección de diseño de idioma. Puedo ver por qué el nombre del tipo debe estar presente si la variable local se modifica por final
o por una anotación, pero no entiendo por qué no se permite un nombre simple de una variable declarada en otro lugar. ¿Alguien tiene alguna idea de por qué se impuso esta restricción?
EDITAR
Varias respuestas hasta ahora parecen sugerir que lo que sucede fuera del ciclo es la razón para diseñar el lenguaje de esta manera. Quizás un examen más detallado de lo que dice JLS aclarará por qué no encuentro esto convincente. Considere este ciclo, donde el State
es una enumeración:
for (State state : State.values()) {
// ...
}
State.values()
es una matriz, por lo que según el JLS, el bucle es funcionalmente idéntico a:
State[] a = State.values();
for (int i = 0; i < a.length; i++) {
State state = a[i];
// ...
}
Ahora bien, este último ciclo podría haberse escrito:
State state;
State[] a = State.values();
for (int i = 0; i < a.length; i++) {
state = a[i];
// ...
}
Conceptualmente, este último bucle (perfectamente legal) podría haber sido utilizado como el equivalente funcional del segundo bucle mejorado for
arriba (el que no compila).
De forma similar, si stateList
es un Iterable<State>
(no una matriz), este ciclo:
for (State state : stateList) {
// ...
}
es funcionalmente idéntico a:
for (Iterator<State> iterator = stateList.iterator(); iterator.hasNext(); ) {
State state = iterator.next();
// ...
}
Al igual que antes, este último ciclo podría haber sido escrito:
State state;
for (Iterator<State> iterator = stateList.iterator(); iterator.hasNext(); ) {
state = iterator.next();
// ...
}
De nuevo, esto podría haberse utilizado como el equivalente funcional de (ilegal):
State state;
for (state : stateList) {
// ...
}
En cada caso, cuando el ciclo sale, el valor de state
está perfectamente definido (si, quizás, inútil). Además, al igual que con el ciclo regular, un bucle forzado mejorado for
usaba un nombre de variable vacío que no estaba definido (por ejemplo, el State state;
la línea State state;
faltaba o estaba fuera del alcance) podría capturarse en tiempo de compilación. Entonces, desde una perspectiva de diseño del lenguaje, ¿cuál es el problema? ¿Por qué los diseñadores de idiomas proscribieron esta construcción?
Muchas decisiones en Java se basan más en el concepto de por qué "Would not" (no lo haría) elimina x. ¿Por qué permitir que su código se confunda moviendo el alcance fuera del ciclo? Si realmente necesitaba acceso al último elemento después, hay formas más limpias.
Supongo que algunos pueden argumentar de una manera u otra en cuanto a proteger a los programadores de ellos mismos, lo veo más cuando Java me protege de las personas que les gusta aprovechar este tipo de cosas.
No es realmente un excelente lenguaje de hobbies, es un excelente lenguaje de desarrollo de equipos en el que el objetivo es hacer que sea lo más fácil posible que el siguiente tipo entienda tu código.
Por ejemplo, vi en un comentario anterior que mucha gente sale de un bucle en cierto punto con un valor. ¿Qué tan claro es eso cuando estás escaneando el código tratando de encontrar un error? Son personas que usan trucos ingeniosos como este de los que realmente quiero que me protejan, no a mí mismo.
Si desea ejecutar algún código de medio ciclo, póngalo en un método y llámelo desde dentro del ciclo.
La falta de lindos trucos a menudo me hace repensar mi código y trabajar un poco más, pero los resultados son siempre más legibles / mantenibles.
Si solo eres un programador único (No en un equipo), desaconsejaría Java. No hace trucos y no verás actualizaciones geniales anuales. Además, es bastante lento para programar (Se mueve mucho tiempo atrapando y corrigiendo errores en el tiempo dedicado a la codificación, frustrando a la gente con sus estrictas reglas (una de las mayores ventajas del lenguaje IMO)
Si quieres algo java, prueba Scala en su lugar. Si te sientes "forzado" a aprender debido a una decisión en el aula, entonces querrás intentar apreciarlo desde el punto de vista del "equipo" y con la mentalidad de que no te verás obligado a usarlo en el futuro.
Observe cómo funciona internamente el bucle for-each, vea ¿Cómo funciona el bucle Java ''for each''?
for(Iterator<String> i = someList.iterator(); i.hasNext(); ) {
String item = i.next();
System.out.println(item);
}
Cada vez que declara el elemento variable String. Por lo tanto, en su caso, es esencialmente
State state;
//and inside
State state = i.next();
que obviamente no funcionará Ahora dentro de la implementación, ellos solo podrían hacer
item = i.next();
pero siempre debes definir ese ítem fuera para cada uno, lo que sería doloroso la mayoría de las veces.
Podrían haber querido eliminar una posible diferencia en la semántica entre el simple para y el mejorado para.
Si tuvieras, digamos, un ciclo regular para:
int i;
for (i=0; i<4; i++)
;
luego, si dejas que el ciclo se ejecute normalmente, obtienes i==4
después del ciclo, que no es válido para la variable de iteración.
Entonces, si pudieras tener:
int i;
for (i : myArray)
;
Supongo que desde el punto de vista de la implementación, sería más fácil si al final fuera igual al último elemento de la matriz. Pero, ¿debería comportarse así o debería haber algún valor inválido, y si es así, qué podría ser? ¿Qué pasa si sales de la última iteración?
Otra posibilidad es que deja más claro de qué se trata ese bucle y cuál es el tipo de elemento de la colección. Por el contrario, lo simple es una construcción "heredada" en cierto sentido, por lo que no podrían haber aplicado una lógica similar sin "romperla" o limitar su flexibilidad.
Obviamente estoy especulando, y podría haber sido una elección de diseño al azar.
Tal vez porque de esta manera, garantiza que el state
estará vacío y no tiene un valor inicial asignado.
Un beneficio / razón de ser es que las variables locales no contaminan su código. Permítanme dar un ejemplo de bucle normal (esto es solo por analogía, no es exacto, así que no uso iterador):
int i;
for(i=0;i<10;i++)
do...something
int j;
for(j=0; i<10; j++)
do...something
Ahora en el código de arriba si miras de cerca encontrarás un error potencial. i
han utilizado por error en el ciclo que itera sobre j
.
Por lo tanto, los bucles mejorados intentan jugar de forma segura al crear las variables localmente, con lo que puede evitar el problema anterior.