Como sair de loops aninhados em Java?



15 Answers

Tecnicamente, a resposta correta é rotular o loop externo. Na prática, se você quiser sair em qualquer ponto dentro de um loop interno, seria melhor externar o código em um método (um método estático, se necessário) e chamá-lo.

Isso pagaria por legibilidade.

O código se tornaria algo assim:

private static String search(...) 
{
    for (Type type : types) {
        for (Type t : types2) {
            if (some condition) {
                // Do something and break...
                return search;
            }
        }
    }
    return null; 
}

Correspondendo ao exemplo da resposta aceita:

 public class Test {
    public static void main(String[] args) {
        loop();
        System.out.println("Done");
    }

    public static void loop() {
        for (int i = 0; i < 5; i++) {
            for (int j = 0; j < 5; j++) {
                if (i * j > 6) {
                    System.out.println("Breaking");
                    return;
                }
                System.out.println(i + " " + j);
            }
        }
    }
}
java loops

Eu tenho uma construção de loop aninhada como esta:

for (Type type : types) {
    for (Type t : types2) {
         if (some condition) {
             // Do something and break...
             break; // Breaks out of the inner loop
         }
    }
}

Agora, como posso sair de ambos os loops. Eu olhei para questões semelhantes, mas nenhuma diz respeito especificamente ao Java. Eu não pude aplicar estas soluções porque a maioria usava gotos.

Eu não quero colocar o laço interno em um método diferente.

Atualização: Eu não quero reexecutar os loops, quando estou terminando, acabo com a execução do bloco de loop.




Eu nunca uso rótulos. Parece uma prática ruim entrar. Aqui está o que eu faria:

boolean finished = false;
for (int i = 0; i < 5 && !finished; i++) {
    for (int j = 0; j < 5; j++) {
        if (i * j > 6) {
            finished = true;
            break;
        }
    }
}



talvez com uma função?

public void doSomething(List<Type> types, List<Type> types2){
  for(Type t1 : types){
    for (Type t : types2) {
      if (some condition) {
         //do something and return...
         return;
      }
    }
  }
}



Se você não gosta de break s e goto s, você pode usar um loop "tradicional" para o for-in, com uma condição extra de aborto:

int a, b;
bool abort = false;
for (a = 0; a < 10 && !abort; a++) {
    for (b = 0; b < 10 && !abort; b++) {
        if (condition) {
            doSomeThing();
            abort = true;
        }
    }
}



Eu prefiro adicionar uma "saída" explícita aos testes de loop. Isso deixa claro para qualquer leitor casual que o loop pode terminar cedo.

boolean earlyExit = false;
for(int i = 0 ; i < 10 && !earlyExit; i++) {
     for(int j = 0 ; i < 10 && !earlyExit; j++) { earlyExit = true; }
}



Você pode quebrar todos os loops sem usar nenhum rótulo: e flags.

É apenas uma solução complicada.

Aqui condition1 é a condição que é usada para quebrar o loop K e J. E condição2 é a condição que é usada para quebrar o loop K, J e I.

Por exemplo:

public class BreakTesting {
    public static void main(String[] args) {
        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 9; j++) {
                for (int k = 0; k < 9; k++) {
                    if (condition1) {
                        System.out.println("Breaking from Loop K and J");
                        k = 9;
                        j = 9;
                    }
                    if (condition2) {
                        System.out.println("Breaking from Loop K, J and I");
                        k = 9;
                        j = 9;
                        i = 9;
                    }
                }
            }
        }
        System.out.println("End of I , J , K");
    }
}



Se estiver dentro de alguma função, por que você simplesmente não a devolve:

for (Type type : types) {
    for (Type t : types2) {
         if (some condition) {
            return value;
         }
    }
}



Abordagem bastante incomum, mas em termos de tamanho de código ( não desempenho ), essa é a coisa mais fácil que você poderia fazer:

for(int i = 0; i++; i < j) {
    if(wanna exit) {
        i = i + j; // if more nested, also add the 
                   // maximum value for the other loops
    }
}



Outra solução, mencionada sem exemplo (ela realmente funciona no código prod).

try {
    for (Type type : types) {
        for (Type t : types2) {
            if (some condition #1) {
                // Do something and break the loop.
                throw new BreakLoopException();
            }
        }
    }
}
catch (BreakLoopException e) {
    // Do something on look breaking.
}

É claro que BreakLoopException deve ser interno, privado e acelerado com rastreamento sem pilha:

private static class BreakLoopException extends Exception {
    @Override
    public StackTraceElement[] getStackTrace() {
        return new StackTraceElement[0];
    }
}



Eu queria responder a this pergunta, mas foi marcada como uma duplicata que me impede de postar também. Então, postando aqui em vez disso!

Se for uma nova implementação, você pode tentar reescrever a lógica como instruções if-else_if-else.

while(keep_going) {

    if(keep_going && condition_one_holds) {
        // code
    }
    if(keep_going && condition_two_holds) {
        // code
    }
    if(keep_going && condition_three_holds) {
        // code
    }
    if(keep_going && something_goes_really_bad) {
        keep_going=false;
    }
    if(keep_going && condition_four_holds) {
        // code
    }
    if(keep_going && condition_five_holds) {
        // code
    }   
}

Caso contrário, você pode tentar definir um sinalizador quando ocorrer essa condição especial e verificar esse sinalizador em cada uma das suas condições de loop.

something_bad_has_happened = false;
while(something is true && !something_bad_has_happened){
    // code, things happen
    while(something else && !something_bad_has_happened){
        // lots of code, things happens
        if(something happened){
            -> Then control should be returned ->
            something_bad_has_happened=true;
            continue;
        }
    }   
    if(something_bad_has_happened) { // things below will not be executed
        continue;
    }

    // other things may happen here as well but will not be executed
    //  once control is returned from the inner cycle
}

HERE! So, while a simple break will not work, it can be made to work using continue.

Se você está simplesmente portando a lógica de uma linguagem de programação para java e quer apenas fazer a coisa funcionar, você pode tentar usar labels




for (int j = 0; j < 5; j++) //inner loop deve ser substituído por for (int j = 0; j < 5 && !exitloops; j++) .

Aqui, neste caso, os loops aninhados completos devem sair se a condição for True . Mas se usarmos exitloops apenas para o loop superior

 for (int i = 0; i < 5 && !exitloops; i++) //upper loop

Em seguida, o loop interno continuará, porque não há sinalizador extra que notifique esse loop interno para sair.

Exemplo: se i = 3 e j=2 , a condição é false . Mas na próxima iteração do laço interno j=3 então a condição (i*j) torna-se 9 que é true mas o laço interno será continuado até j tornar-se 5 .

Então, deve usar exitloops para os loops internos também.

boolean exitloops = false;
for (int i = 0; i < 5 && !exitloops; i++) { //here should exitloops as a Conditional Statement to get out from the loops if exitloops become true. 
    for (int j = 0; j < 5 && !exitloops; j++) { //here should also use exitloops as a Conditional Statement. 
        if (i * j > 6) {
            exitloops = true;
            System.out.println("Inner loop still Continues For i * j is => "+i*j);
            break;
        }
        System.out.println(i*j);
    }
}



Você pode fazer o seguinte:

  1. definir uma variável local como false

  2. definir essa variável true no primeiro loop, quando você quer quebrar

  3. então você pode verificar no loop externo, se a condição está definida e, em seguida, interromper o loop externo também.

    boolean isBreakNeeded = false;
    for (int i = 0; i < some.length; i++) {
        for (int j = 0; j < some.lengthasWell; j++) {
            //want to set variable if (){
            isBreakNeeded = true;
            break;
        }
    
        if (isBreakNeeded) {
            break; //will make you break from the outer loop as well
        }
    }



Mesmo criando um sinalizador para loop externo e verificando que após cada execução do loop interno pode ser a resposta.

Como isso :

for (Type type : types) {
    boolean flag=false;
    for (Type t : types2) {
        if (some condition) {
            // Do something and break...
            flag=true;
            break; // Breaks out of the inner loop
        }
    }
    if(flag)
        break;
}



Java não possui um recurso goto como existe em C ++. Mas ainda assim, goto é uma palavra reservada em Java. Eles podem implementá-lo no futuro. Para sua pergunta, a resposta é que existe algo chamado label em Java, ao qual você pode aplicar uma instrução continue e break . Encontre o código abaixo:

public static void main(String ...args) {
    outerLoop: for(int i=0;i<10;i++) {
    for(int j=10;j>0;j--) {
        System.out.println(i+" "+j);
        if(i==j) {
            System.out.println("Condition Fulfilled");
            break outerLoop;
        }
    }
    }
    System.out.println("Got out of the outer loop");
}



Verifique se o loop interno é encerrado com uma instrução if, verificando a variável do loop interno. Você também pode criar outra variável, como um booleano, para verificar se o loop interno é encerrado.

Neste exemplo, ele usa a variável do loop interno para verificar se ele foi encerrado:

int i, j;
for(i = 0; i < 7; i++){

for(j = 0; j < 5; j++) {

     if (some condition) {
         // Do something and break...
         break; // Breaks out of the inner loop
     }
}
     if(j < 5){    // Checks if inner loop wasn't finished
     break;    // Breaks out of the outer loop   
     } 
}



Related


Tags

java   loops