2011-07-11 14 views
9

Tengo 2 fors, después del anidado porque tengo un código que no quiero ejecutar si una condición es verdadera dentro del anidado. Si utilizo break, ese código se ejecutará, entonces (como aprendí en SCJP) utilicé continue label; para el exterior. ¿Es esto un uso obsoleto de Java? ¿Pasado de moda? Alguien sugirió usar recursividad u otra cosa, pero para mí esto es perfectamente normal, simple, actualizado y la forma perfecta de hacerlo.La etiqueta para continuar con Java está obsoleta?

here: 
for (bla bla) { 
    for (bla bla) { 
     if (whatever) continue here; 
    } 
// some code I don't want to execute if whatever is true 
} 

Gracias

Editado:
Si reformular mi pregunta: ¿Cómo se puede 'navegar' entre varios Fors anidados? Este enfoque sería la forma 'recomendada'? porque esto es lo que dice en el Libro SCJP. Si no ... ¿significaría esto que Katherine Sierra y Bert Bates son incorrectos?

Edited2:
¿Por qué es continue label; desanimado? Quiero una respuesta de los conceptos o funcionamiento interno de programación orientada a objetos o Java, lo que podría salir mal ..

+2

Si NECESITA navegar entre múltiples bucles anidados, entonces no solo es la manera recomendada sino la única. Entonces ellos tienen razón Aunque recomendaría evitar navegar entre múltiples bucles anidados. –

Respuesta

4

La respuesta es: depende. Si te encuentras usando continue mucho, entonces puede ser una señal de que tu código necesita un refactor. Sin embargo, en el escenario que ha dado, parece ser un buen lugar para usarlo.

3

, diría que es desalentado. Todavía tiene usos válidos donde las alternativas son más complejos o propenso a errores (es decir, no una mejora)

+0

+1 aunque no creo que se desaliente romper/continuar con una etiqueta. El olor suele ser, aunque no siempre, el bucle anidado. – Kaj

+2

bien en mi caso, creo que esta es la manera más simple, ya sabes .. BESO .. –

+1

@Kaj. Algo en desacuerdo. El doble lazo anidado, si es suficientemente simple, no huele demasiado. La necesidad de un ETIQUETADO continúa aumenta el tiempo de olor para considerar la refactorización, moviendo el bucle interno a su propio método. Cosmin: si el código es tan simple como tu ejemplo, entonces sí, KISS. Si el método se vuelve más complejo, explique los detalles internos, de modo que la estructura externa se pueda leer de un vistazo. Y elimine la necesidad de continuar etiquetado como parte de esa legibilidad. – ToolmakerSteve

5

Refactorizaría para hacerlo más legible.

Ejemplo:

if (!checkWhatever()) { 
    // some code I don't want to execute if whatever is true 
} 
boolean checkWhatever() { 
    for (bla bla) { 
     for (bla bla) { 
      if (whatever) return false; 
     } 
    } 
    return true; 
} 
+0

y si tiene 5 niveles de anidamiento? Esta solución estaría bien para un caso particular. Quiero una generalización. –

+4

@Cosmin Vacaroiu 5 bucles anidados? Suena como un problema de diseño, y debe ser refactorizado. – Kaj

+6

No hay una forma general de reemplazar el "continuar etiquetando". Por otro lado, siempre hay alguna manera de reemplazarlo. –

2

Con referencia a su edición 2, que siempre va a parecer un poco dudoso porque viola una ortodoxia de programación orientado a objetos mayores que: 'programación estructurada' (ver http://en.wikipedia.org/wiki/Structured_programming). También huele a goto, y todos los buenos programadores saben que necesitan confesarse si dejan entrar su código.

Podría haber cierta preocupación de que podría hacer más difícil para un compilador para analizar el flujo de control de una función, pero es el tipo de herramienta que normalmente se acostumbra por razones de eficiencia. Por ejemplo, la implementación de Apache de java.lang.String lo utiliza en esta función que es al menos la intención de ser una optimización:

/* 
* An implementation of a String.indexOf that is supposed to perform 
* substantially better than the default algorithm if the "needle" (the 
* subString being searched for) is a constant string. 
* 
* For example, a JIT, upon encountering a call to String.indexOf(String), 
* where the needle is a constant string, may compute the values cache, md2 
* and lastChar, and change the call to the following method. 
*/ 
@SuppressWarnings("unused") 
private static int indexOf(String haystackString, String needleString, 
     int cache, int md2, char lastChar) { 
    char[] haystack = haystackString.value; 
    int haystackOffset = haystackString.offset; 
    int haystackLength = haystackString.count; 
    char[] needle = needleString.value; 
    int needleOffset = needleString.offset; 
    int needleLength = needleString.count; 
    int needleLengthMinus1 = needleLength - 1; 
    int haystackEnd = haystackOffset + haystackLength; 
    outer_loop: for (int i = haystackOffset + needleLengthMinus1; i < haystackEnd;) { 
     if (lastChar == haystack[i]) { 
      for (int j = 0; j < needleLengthMinus1; ++j) { 
       if (needle[j + needleOffset] != haystack[i + j 
         - needleLengthMinus1]) { 
        int skip = 1; 
        if ((cache & (1 << haystack[i])) == 0) { 
         skip += j; 
        } 
        i += Math.max(md2, skip); 
        continue outer_loop; 
       } 
      } 
      return i - needleLengthMinus1 - haystackOffset; 
     } 

     if ((cache & (1 << haystack[i])) == 0) { 
      i += needleLengthMinus1; 
     } 
     i++; 
    } 
    return -1; 
} 
0

Refactor para que sea más fácil de leer, colocando el bucle interno en su propio método:

for (bla bla) { 
    DoStuff(); 
} 
void DoStuff() { 
    for (bla bla) { 
    if (whatever) return; 
    } 
    // some code to execute when whatever is false. 
} 

El principio: Si un método se vuelve lo suficientemente complejo como para requerir el etiquetado de un bloque, considerar refactorización parte de ese método en un método separado, de manera que no se necesita ninguna etiqueta.

Del mismo modo, no es prudente hacer que los métodos que son tres bucles de profundidad. A menos que los bucles sean muy simples. Incluso si no se necesitan etiquetas. Asegúrese de que la construcción de flujo más externa (un bucle, o un if/else, o un interruptor) sea fácil de leer, ocultando la complejidad dentro de otros métodos. Incluso si esos métodos solo son llamados desde un solo lugar.

+0

@Mikael tiene la idea correcta; sin embargo, su refactorización es incorrecta, no conserva el comportamiento del original, "// algún código" es parte del bucle interno, no del bucle externo. Propuse este cambio como una edición de su publicación, junto con mis párrafos explicativos, pero eso fue rechazado por los revisores como un cambio/cambio de sentido de publicación demasiado importante. Entonces publico aquí como una respuesta separada. – ToolmakerSteve

0

Utilice un valor lógico llamado 'éxito' o algo por el estilo. Es mucho más fácil de leer y seguir el flujo. Gotos solo debe usarse para el manejo de errores.

boolean success = true; 
for(int outer = 0; (outer <= outerLimit) && sucess; outer++) 
{ 
    for(int inner = 0; (inner <= innerLimit) && success; inner++) 
    { 
     if(!doInnerStuff()) 
     { 
      success = false; 
     } 
    } 

    if(success) 
    { 
     success = doOuterStuff(); 
    } 
} 
+0

es probable que desee 'break' after' success = false' o agregar una condición para asegurarse de salir del bucle interno. – njzk2

+0

sí, me perdí el éxito en el otro ciclo for. – Evvo

Cuestiones relacionadas