Capítulo 002 Ejercicio 018 (For etiquetado)

// Programa que muestra el bucle "for etiquetado" de Java

/** La palabra clave "goto" ha estado presente en los lenguajes de programación desde los comienzos.
* Sin duda, el "goto" era la genésis del control de los programadores en el lenguaje ensamblador:
* "Si se da la condición A, entonces saltar aquí, sino, saltar ahí". Si se lee el código ensamblador
* generado al final por cualquier compilador, se verá que el control del programa contiene muchos saltos.
* Sin embargo, un "goto" es un salto a nivel de código fuente, y eso es lo que le ha traido tan mala
* reputación. Si un programa salta siempre de un lado a otro, ¿no hay forma de reorganizarlo de manera que
* el flujo de control no dé tantos saltos? "goto" cayó en desgracia con la publicación del famoso artículo
* "El Goto considerado dañino", de Edsger Dijkstra, y desde entonces, la prohibición del "goto" ha sido
* un deporte popular, con los partidarios de la palabra clave repudiada buscando guarida.
*
* Como es típico en situaciones como ésta, el terreno imparcial es el más fructífero. El problema no es
* el uso del "goto", sino el suso excesivo del "goto" - en raras ocasiones el "goto" es de hecho la mejor
* manera de estructurar el flujo del programa.
*
* Aunque "goto" es una palabra reservada en Java, no se utiliza en el lenguaje; Java no tiene "goto".
* Sin embrago, tiene algo que se parece un poco a un salto atado vinculado a las palabras clave "break" y
* "continue". No es un salto sino más bien una forma de romper una sentencia de iteración. El motivo por
* el que aparece muy a menudo en discusiones relacionadas con el "goto", es que utiliza el mismo mecanismo:
* una etiqueta.
*
* Una etiqueta es un identificador seguido de dos puntos, como ésta:
*
* etiqueta1:
*
* El único sitio en el que una etiqueta es útil en Java es justo antes de una sentencia de iteración. Y eso
* significa justo antes - no hace ningún bien poner cualquier otra sentencia entre la etiqueta y la iteración.
* Y la única razón para poner una etiqueta antes de una iteración es si se va a anidar otra iteración o un
* "switch" dentro. Eso es porque las palabra "break" y "continue" únicamente interrumpirán normalmente al
* bucle actual, pero cuando se usan con una etiqueta, interrumpirán a los bucles hasta donde exista la
* etiqueta:
*
* etiqueta1:
* iteración - externa {
* iteración - interna {
* //...
* break; //1
* //...
* continue; //2
* //...
* continue etiqueta1; //3
* //...
* break etiqueta1; //4
* }
* }
*
* En el casi 1, el break rompe la iteración interna, pasando a la iteración exterior. En el caso 2, el continue
* hace volver al principio de la iteración interna. Pero en el caso 3, el continue etiqueta1 rompe tanto la
* iteración interna, como la externa, retrocediendo hasta etiqueta1. Posteriormente, de hecho, continúa la
* iteración, pero empezando en la iteración exterior. En el caso 4, el break etiqueta1 también rompe el bucle
* haciendo volver hasta etiqueta1, pero no vuelve a entrar en la iteración. De hecho, rompe ambas iteraciones.
*
* He aquí un ejemplo de utilización de bucles for.
*/

public class ForEtiquetado{
public static void main(String args[]){

int i = 0;
externo: // Aqui no puede haber sentencias
for( ; true ; ){ // Bucle infinito
interno: // Aqui no puede haber sentencias
for( ; i < 10; i++){

visualizar("i = " + i);

if(i == 2){
visualizar("Continuar");
continue;
}

if(i == 3){
visualizar("Salir");
i++; // En caso contrario "i" no se incrementa nunca
break;
}

if(i == 7){
visualizar("Continuar el externo");
i++; // En caso contrario "i" no se incrementa nunca
continue externo;
}

if(i == 8) {
visualizar("Salir externo");
break externo;
}

for(int k = 0; k < 5; k++){
if(k == 3){
visualizar("Continuar el interno");
continue interno;
}
}

}
}

// Aqui no se puede hacer break o continue a etiquetas
}

static void visualizar(String s){
System.out.println(s);
}
}

/** Este ejemplo usa el método visualizar( ) que ha sido definido en los otros ejemplos.
*
* Nótese que "break" sale del bucle "for", y que la expresión de incremento no se da hasta
* acabar de pasar por el bucle "for". Dado que "break" se salta la expresión e incremento,
* el incremento se da directamente en el caso de i==3. La sentencia "continuar externo" en el
* caso de i==7 va también a la parte superior del bucle, y se salta también el incremento,
* por lo que también se incrementa directamente.
*
* He aquí la salida:
*
* --------------------Configuration: --------------------
* i = 0
* Continuar el interno
* i = 1
* Continuar el interno
* i = 2
* Continuar
* i = 3
* Salir
* i = 4
* Continuar el interno
* i = 5
* Continuar el interno
* i = 6
* Continuar el interno
* i = 7
* Continuar el externo
* i = 8
* Salir externo
*
* Process completed.
*
* Si no fuera por la sentencia "break externo", no habría manera de salir del bloque externo desde
* el bucle interno, dado que "break" por si misma puede romper únicamente el bucle más interno. (Y lo
* mismo ocurre con "continue").
*
* Por supuesto, en los casos en los que salir de un bucle implique también salir del método, uno
* puede usar simplemente un "return".
*
**/