Pregunta ¿Por qué la variable local de un bucle forzado mejorado debe ser local? [duplicar]


Esta pregunta ya tiene una respuesta aquí:

De acuerdo con la Especificación del lenguaje Java, § 14.14.2, la variable de un mejorado for el bucle 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 es modificada por final o mediante 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. Considera este ciclo, donde State es una enumeración:

for (State state : State.values()) {
    // ...
}

State.values() es una matriz, por lo que según el JLS, el ciclo 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 (perfectamente legal) bucle podría haber sido utilizado como el equivalente funcional del segundo mejorado for loop arriba (el que no compila).

Del mismo modo, 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();
    // ...
}

Nuevamente, esto podría se han 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 bucle regular, una mejora for bucle utilizando un nombre de variable simple que no se definió (por ejemplo, la línea State state; faltaba o estaba fuera del alcance) podría ser capturado 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?


32
2017-11-20 20:09


origen


Respuestas:


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 ha sido utilizado por error en el bucle que se repite 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.


9
2017-11-20 23:57



Mira cómo funciona internamente el bucle for-each, mira ¿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.


11
2017-11-20 20:20



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.


7
2017-11-21 05:39



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++)
    ;

entonces, si dejas que el ciclo se ejecute normalmente, obtienes eso 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 i fueron iguales 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.


5
2017-11-20 21:08



Tal vez porque de esta manera, garantiza que state estará vacío y no tiene un valor inicial asignado.


3
2017-11-20 20:17