@harigm: ¿Puede dar un ejemplo del tipo de código que escribiría sigoto estuviera disponible en Java? Creo que ahí radica la cuestión más importante.
polygenelubricants
3
@harigm: Segundo polygene, ¿podría actualizar su pregunta para incluir por qué su programa necesita un goto?
Todos el
13
La gente siempre habla de no usar nunca un goto, pero creo que hay un caso de uso del mundo real realmente bueno que es bastante conocido y utilizado. Es decir, asegurarse de ejecutar algún código antes de devolver una función. Por lo general, su lanzamiento cerraduras o lo que no, pero en mi caso me encantaría poder saltar a un descanso justo antes del regreso para poder hacer la limpieza obligatoria requerida. Por supuesto, un programa lleno de goto por todas partes sería horrible, pero si se limita a los cuerpos de método, no parece tan malo siempre y cuando siga una convención (solo salte al final de las funciones, nunca retroceda)
Matt Wolfe
7
Estás en buena compañía. Linus Torvalds ha defendido apasionadamente goto kerneltrap.org/node/553 . Sin duda la omisión más notable del Proyecto Coin.
Fletch
7
@MattWolfe no lo intenta, ¿finalmente hace el trabajo en ese ejemplo?
¿Por qué no debería necesitar la funcionalidad goto en un código diseñado correctamente?
Rogermushroom
13
Porque el ensamblaje es el único autorizado para usarlo. Una declaración while, una declaración for, un do-while, un foreach, una llamada de función, todas estas son declaraciones GOTO utilizadas de una manera controlada y predecible. En el nivel del ensamblador, siempre será GOTO, pero no debería necesitar la funcionalidad que le brinda GOTO puro; su única ventaja sobre las funciones y las declaraciones de bucle / control es que le permite saltar en medio de cualquier código, en cualquier lugar . Y esa "ventaja" es en sí misma la definición de "código espagueti".
No hay ningún equivalente directo al gotoconcepto en Java. Hay algunas construcciones que le permiten hacer algunas de las cosas que puede hacer con un clásico goto.
Las declaraciones breaky le continuepermiten saltar de un bloque en un bucle o instrucción de cambio.
Una declaración etiquetada y le break <label>permite saltar de una declaración compuesta arbitraria a cualquier nivel dentro de un método dado (o bloque inicializador).
Si etiqueta una declaración de bucle, puede continue <label>continuar con la siguiente iteración de un bucle externo desde un bucle interno.
Lanzar y capturar excepciones le permite saltar (efectivamente) de muchos niveles de una llamada a un método. (Sin embargo, las excepciones son relativamente caras y se consideran una mala forma de realizar un control de flujo "ordinario" 1 ).
Y por supuesto, hay return .
Ninguna de estas construcciones de Java le permite ramificarse hacia atrás o hacia un punto en el código en el mismo nivel de anidamiento que la declaración actual. Todos saltan uno o más niveles de anidación (alcance) y todos (excepto continue) saltan hacia abajo. Esta restricción ayuda a evitar el síndrome de goto "código espagueti" inherente al antiguo código 2 de BASIC, FORTRAN y COBOL .
1- La parte más cara de las excepciones es la creación real del objeto de excepción y su seguimiento de pila. Si realmente, realmente necesita utilizar el manejo de excepciones para el control de flujo "normal", puede preasignar / reutilizar el objeto de excepción o crear una clase de excepción personalizada que anule el fillInStackTrace()método. La desventaja es que la excepciónprintStackTrace() métodos de no le darán información útil ... en caso de que alguna vez necesite llamarlos.
2 - El síndrome del código espagueti generó el enfoque de programación estructurada , en el que limitaba el uso de las construcciones de lenguaje disponibles. Esto podría aplicarse a BASIC , Fortran y COBOL , pero requería cuidado y disciplina. Deshacerse de él por gotocompleto fue una solución pragmáticamente mejor. Si lo guardas en un idioma, siempre habrá algún payaso que abusará de él.
Las construcciones de bucle como while (...) {} y for (...) {} le permiten repetir bloques de código sin saltar explícitamente a una ubicación arbitraria. Además, las llamadas a métodos myMethod () le permiten ejecutar el código que se encuentra en otro lugar y volver al bloque actual cuando haya terminado. Todos estos pueden usarse para reemplazar la funcionalidad de goto mientras se previene el problema común de no devolver lo que permite goto.
Chris Nava
@Chris: eso es cierto, pero la mayoría de los lenguajes que admiten GOTO también tienen análogos más cercanos a las construcciones de bucle de Java.
Stephen C
1
@Chris: el FORTRAN clásico tiene bucles 'for' y el COBOL clásico también tiene construcciones de bucle (aunque no puedo recordar los detalles). Solo el BASIC clásico no tiene construcciones de bucle explícitas ...
Stephen C
31
Solo por diversión, aquí hay una implementación GOTO en Java.
Si bien. Todo lo que solo pueda implementarse mediante piratería de código de bytes no es realmente Java ...
Stephen C
¿Hay algo similar que admita etiquetas en lugar de números de línea?
Behrouz.M
1
El vínculo a una implementación está roto.
LarsH
17
Si bien algunos comentaristas y votantes negativos argumentan que esto no es goto , el código de bytes generado a partir de las siguientes declaraciones de Java realmente sugiere que estas declaraciones realmente expresan la semántica de goto .
Específicamente, el do {...} while(true); compiladores de Java optimizan ciclo del segundo ejemplo para no evaluar la condición del ciclo.
Saltando hacia adelante
label: {
// do stuffif (check) break label;
// do more stuff
}
En bytecode:
2 iload_1 [check]
3 ifeq 6// Jumping forward6 ..
Saltando hacia atrás
label: do {
// do stuffif (check) continue label;
// do more stuffbreak label;
} while(true);
¿Cómo salta hacia atrás el do / while? Todavía se sale del bloque. Ejemplo de contador: label: do {System.out.println ("Backward"); continuar etiqueta;} while (falso); Creo que en tu ejemplo el while (verdadero) es el responsable del salto hacia atrás.
Ben Holland
@BenHolland: continue labeles el salto hacia atrás
Lukas Eder
Todavía no estoy convencido. La instrucción continue omite la iteración actual de un bucle for, while o do-while. Continuar salta al final del cuerpo del bucle, que luego se evalúa para la expresión booleana que controla el bucle. El tiempo es lo que está saltando hacia atrás, no el continuar. Ver docs.oracle.com/javase/tutorial/java/nutsandbolts/branch.html
Ben Holland
@BenHolland: Técnicamente tienes razón. Desde una perspectiva lógica, si // do stuffy // do more stuffson las declaraciones de interés, continue label"tiene el efecto" de saltar hacia atrás (debido a la while(true)declaración, por supuesto). Sin embargo, no sabía que esta era una pregunta tan precisa ...
Lukas Eder
2
@BenHolland: Actualicé la respuesta. El while(true)compilador traduce el en una gotooperación de código de bytes. Como truees un literal constante, el compilador puede hacer esta optimización y no tiene que evaluar nada. Entonces, mi ejemplo realmente es un goto, saltando hacia atrás ...
Lukas Eder
5
Si realmente desea algo como declaraciones goto, siempre puede intentar dividir a bloques con nombre.
Tienes que estar dentro del alcance del bloque para romper con la etiqueta:
namedBlock: {
if (j==2) {
// this will take you to the label abovebreak namedBlock;
}
}
No te daré un sermón sobre por qué deberías evitar los goto, supongo que ya sabes la respuesta a eso.
Intenté implementar esto en mi pregunta SO vinculada aquí . En realidad, no lo lleva a la "etiqueta de arriba", tal vez malinterpreté las declaraciones del autor, pero para mayor claridad agregaré que lo lleva al final del bloque exterior (el bloque "etiquetado"), que está debajo donde te estás rompiendo. Por tanto, no se puede "romper" hacia arriba. Al menos eso es lo que yo entiendo.
Esto dará como resultado una StackOverFlowException si lo ejecuta el tiempo suficiente, por lo que mi necesidad de ir a.
Kevin Parker
3
@Kevin: ¿Cómo conducirá esto a un desbordamiento de pila? No hay recursividad en este algoritmo ...
Lukas Eder
1
Esto se parece mucho a la prueba original de que cualquier programa se puede escribir sin usar "goto", convirtiéndolo en un bucle while con una variable de "etiqueta" que es diez veces peor que cualquier goto.
gnasher729
3
StephenC escribe:
Hay dos construcciones que le permiten hacer algunas de las cosas que puede hacer con un goto clásico.
Uno mas...
Matt Wolfe escribe:
La gente siempre habla de no usar nunca un goto, pero creo que hay un caso de uso del mundo real realmente bueno que es bastante conocido y usado. Es decir, asegurarse de ejecutar algún código antes de que una función regrese. Por lo general, su lanzamiento cerraduras o lo que no, pero en mi caso me encantaría poder saltar a un descanso justo antes del regreso para poder hacer la limpieza obligatoria requerida.
try {
// do stuffreturn result; // or break, etc.
}
finally {
// clean up before actually returning, even though the order looks wrong.
}
El bloque finalmente siempre se ejecuta cuando sale el bloque try. Esto asegura que el bloque finalmente se ejecute incluso si ocurre una excepción inesperada. Pero finalmente es útil para algo más que el manejo de excepciones: le permite al programador evitar que el código de limpieza se omita accidentalmente por un retorno, continuación o interrupción. Poner el código de limpieza en un bloque final siempre es una buena práctica, incluso cuando no se anticipan excepciones.
La pregunta tonta de la entrevista asociada con finalmente es: Si regresa de un bloque try {}, pero también tiene un retorno en su finalmente {}, ¿qué valor se devuelve?
No estoy de acuerdo con que esa sea una pregunta tonta de la entrevista. Un programador de Java experimentado debe saber lo que sucede, aunque solo sea para comprender por qué poner un returnen un finallybloque es una mala idea. (E incluso si el conocimiento no es estrictamente necesario, me preocuparía un programador que no tuviera la curiosidad de averiguarlo ...)
Stephen C
1
Lo más fácil es:
int label = 0;
loop:while(true) {
switch(state) {
case0:
// Some code
state = 5;
break;
case2:
// Some code
state = 4;
break;
...
default:
break loop;
}
}
Java no lo tiene goto, porque hace que el código no esté estructurado y sea poco claro para leer. Sin embargo, puede utilizar breaky continuecomo forma civilizada de goto sin sus problemas.
Saltar hacia adelante usando el descanso -
ahead: {
System.out.println("Before break");
break ahead;
System.out.println("After Break"); // This won't execute
}
// After a line break ahead, the code flow starts from here, after the ahead block
System.out.println("After ahead");
Su ejemplo de saltar hacia atrás usando continue es incorrecto. No puede utilizar "continuar" fuera del cuerpo de un bucle, ya que provoca un error de compilación. Dentro de un bucle, sin embargo, continue simplemente salta el bucle condicional. Entonces, algo como while (verdadero) {continuar;} sería un bucle infinito, pero también lo es while (verdadero) {} para el caso.
goto
estuviera disponible en Java? Creo que ahí radica la cuestión más importante.Respuestas:
Puede usar una declaración BREAK etiquetada :
search: for (i = 0; i < arrayOfInts.length; i++) { for (j = 0; j < arrayOfInts[i].length; j++) { if (arrayOfInts[i][j] == searchfor) { foundIt = true; break search; } } }
Sin embargo, en un código diseñado correctamente, no debería necesitar la funcionalidad GOTO.
fuente
No hay ningún equivalente directo al
goto
concepto en Java. Hay algunas construcciones que le permiten hacer algunas de las cosas que puede hacer con un clásicogoto
.break
y lecontinue
permiten saltar de un bloque en un bucle o instrucción de cambio.break <label>
permite saltar de una declaración compuesta arbitraria a cualquier nivel dentro de un método dado (o bloque inicializador).continue <label>
continuar con la siguiente iteración de un bucle externo desde un bucle interno.return
.Ninguna de estas construcciones de Java le permite ramificarse hacia atrás o hacia un punto en el código en el mismo nivel de anidamiento que la declaración actual. Todos saltan uno o más niveles de anidación (alcance) y todos (excepto
continue
) saltan hacia abajo. Esta restricción ayuda a evitar el síndrome de goto "código espagueti" inherente al antiguo código 2 de BASIC, FORTRAN y COBOL .1- La parte más cara de las excepciones es la creación real del objeto de excepción y su seguimiento de pila. Si realmente, realmente necesita utilizar el manejo de excepciones para el control de flujo "normal", puede preasignar / reutilizar el objeto de excepción o crear una clase de excepción personalizada que anule el
fillInStackTrace()
método. La desventaja es que la excepciónprintStackTrace()
métodos de no le darán información útil ... en caso de que alguna vez necesite llamarlos.2 - El síndrome del código espagueti generó el enfoque de programación estructurada , en el que limitaba el uso de las construcciones de lenguaje disponibles. Esto podría aplicarse a BASIC , Fortran y COBOL , pero requería cuidado y disciplina. Deshacerse de él por
goto
completo fue una solución pragmáticamente mejor. Si lo guardas en un idioma, siempre habrá algún payaso que abusará de él.fuente
Solo por diversión, aquí hay una implementación GOTO en Java.
¿Tengo que añadir "no lo use"?
fuente
Math.random()
puede devolver 0. Debería ser> =Si bien algunos comentaristas y votantes negativos argumentan que esto no es goto , el código de bytes generado a partir de las siguientes declaraciones de Java realmente sugiere que estas declaraciones realmente expresan la semántica de goto .
Específicamente, el
do {...} while(true);
compiladores de Java optimizan ciclo del segundo ejemplo para no evaluar la condición del ciclo.Saltando hacia adelante
label: { // do stuff if (check) break label; // do more stuff }
En bytecode:
2 iload_1 [check] 3 ifeq 6 // Jumping forward 6 ..
Saltando hacia atrás
label: do { // do stuff if (check) continue label; // do more stuff break label; } while(true);
En bytecode:
2 iload_1 [check] 3 ifeq 9 6 goto 2 // Jumping backward 9 ..
fuente
continue label
es el salto hacia atrás// do stuff
y// do more stuff
son las declaraciones de interés,continue label
"tiene el efecto" de saltar hacia atrás (debido a lawhile(true)
declaración, por supuesto). Sin embargo, no sabía que esta era una pregunta tan precisa ...while(true)
compilador traduce el en unagoto
operación de código de bytes. Comotrue
es un literal constante, el compilador puede hacer esta optimización y no tiene que evaluar nada. Entonces, mi ejemplo realmente es un goto, saltando hacia atrás ...Si realmente desea algo como declaraciones goto, siempre puede intentar dividir a bloques con nombre.
Tienes que estar dentro del alcance del bloque para romper con la etiqueta:
namedBlock: { if (j==2) { // this will take you to the label above break namedBlock; } }
No te daré un sermón sobre por qué deberías evitar los goto, supongo que ya sabes la respuesta a eso.
fuente
public class TestLabel { enum Label{LABEL1, LABEL2, LABEL3, LABEL4} /** * @param args */ public static void main(String[] args) { Label label = Label.LABEL1; while(true) { switch(label){ case LABEL1: print(label); case LABEL2: print(label); label = Label.LABEL4; continue; case LABEL3: print(label); label = Label.LABEL1; break; case LABEL4: print(label); label = Label.LABEL3; continue; } break; } } public final static void print(Label label){ System.out.println(label); }
fuente
StephenC escribe:
Uno mas...
Matt Wolfe escribe:
try { // do stuff return result; // or break, etc. } finally { // clean up before actually returning, even though the order looks wrong. }
http://docs.oracle.com/javase/tutorial/essential/exceptions/finally.html
La pregunta tonta de la entrevista asociada con finalmente es: Si regresa de un bloque try {}, pero también tiene un retorno en su finalmente {}, ¿qué valor se devuelve?
fuente
return
en unfinally
bloque es una mala idea. (E incluso si el conocimiento no es estrictamente necesario, me preocuparía un programador que no tuviera la curiosidad de averiguarlo ...)Lo más fácil es:
int label = 0; loop:while(true) { switch(state) { case 0: // Some code state = 5; break; case 2: // Some code state = 4; break; ... default: break loop; } }
fuente
Pruebe el siguiente código. Esto funciona para mi.
for (int iTaksa = 1; iTaksa <=8; iTaksa++) { // 'Count 8 Loop is 8 Taksa strTaksaStringStar[iCountTaksa] = strTaksaStringCount[iTaksa]; LabelEndTaksa_Exit : { if (iCountTaksa == 1) { //If count is 6 then next it's 2 iCountTaksa = 2; break LabelEndTaksa_Exit; } if (iCountTaksa == 2) { //If count is 2 then next it's 3 iCountTaksa = 3; break LabelEndTaksa_Exit; } if (iCountTaksa == 3) { //If count is 3 then next it's 4 iCountTaksa = 4; break LabelEndTaksa_Exit; } if (iCountTaksa == 4) { //If count is 4 then next it's 7 iCountTaksa = 7; break LabelEndTaksa_Exit; } if (iCountTaksa == 7) { //If count is 7 then next it's 5 iCountTaksa = 5; break LabelEndTaksa_Exit; } if (iCountTaksa == 5) { //If count is 5 then next it's 8 iCountTaksa = 8; break LabelEndTaksa_Exit; } if (iCountTaksa == 8) { //If count is 8 then next it's 6 iCountTaksa = 6; break LabelEndTaksa_Exit; } if (iCountTaksa == 6) { //If count is 6 then loop 1 as 1 2 3 4 7 5 8 6 --> 1 iCountTaksa = 1; break LabelEndTaksa_Exit; } } //LabelEndTaksa_Exit : { } // "for (int iTaksa = 1; iTaksa <=8; iTaksa++) {"
fuente
Utilice un descanso etiquetado como alternativa a goto.
fuente
Java no lo tiene
goto
, porque hace que el código no esté estructurado y sea poco claro para leer. Sin embargo, puede utilizarbreak
ycontinue
como forma civilizada de goto sin sus problemas.Saltar hacia adelante usando el descanso -
ahead: { System.out.println("Before break"); break ahead; System.out.println("After Break"); // This won't execute } // After a line break ahead, the code flow starts from here, after the ahead block System.out.println("After ahead");
Salida :
Saltar hacia atrás usando continuar
before: { System.out.println("Continue"); continue before; }
Esto dará como resultado un bucle infinito, ya que cada vez que
continue before
se ejecuta la línea , el flujo de código comenzará de nuevobefore
.fuente