Rottura di loop annidati in Java

Ho un costrutto loop annidato in questo modo:

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

Ora come posso uscire da entrambi i cicli. Ho esaminato domande simili, ma nessuna riguarda specificamente Java. Non ho potuto applicare queste soluzioni perché il gotos più usato.

Non voglio mettere il ciclo interno in un altro modo.

Aggiornamento: non voglio rieseguire i loop, quando si rompono ho finito con l’esecuzione del blocco del ciclo.

Come altri rispondenti, preferirei sicuramente mettere il ciclo interno in un metodo diverso. Questa risposta mostra solo come possono essere soddisfatti i requisiti della domanda.

Puoi usare l’ break con un’etichetta per il ciclo esterno. Per esempio:

 public class Test { public static void main(String[] args) { outerloop: for (int i=0; i < 5; i++) { for (int j=0; j < 5; j++) { if (i * j > 6) { System.out.println("Breaking"); break outerloop; } System.out.println(i + " " + j); } } System.out.println("Done"); } } 

Questo stampa:

 0 0 0 1 0 2 0 3 0 4 1 0 1 1 1 2 1 3 1 4 2 0 2 1 2 2 2 3 Breaking Done 

Tecnicamente la risposta corretta è etichettare il ciclo esterno. In pratica, se si desidera uscire in qualsiasi punto all’interno di un ciclo interno, sarebbe meglio esternalizzare il codice in un metodo (un metodo statico se necessario) e quindi chiamarlo.

Ciò pagherebbe per la leggibilità.

Il codice diventerebbe qualcosa del genere:

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

Corrispondenza dell’esempio per la risposta accettata:

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

Puoi utilizzare un blocco denominato attorno ai loop:

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

Non uso mai le etichette. Sembra una ctriggers pratica in cui entrare. Ecco cosa farei:

 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; } } } 

Puoi usare le etichette:

 label1: for (int i = 0;;) { for (int g = 0;;) { break label1; } } 

forse con una funzione?

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

Puoi utilizzare una variabile temporanea:

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

A seconda della funzione, puoi anche uscire / tornare dal ciclo interno:

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

Se non ti piace break s and goto s, puoi usare un ciclo “tradizionale” invece di “for-in”, con una condizione di interruzione aggiuntiva:

 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; } } } 

Avevo bisogno di fare una cosa simile, ma ho scelto di non usare il ciclo avanzato per farlo.

 int s = type.size(); for (int i = 0; i < s; i++) { for (int j = 0; j < t.size(); j++) { if (condition) { // do stuff after which you want // to completely break out of both loops s = 0; // enables the _main_ loop to terminate break; } } } 

Preferisco aggiungere un esplicito “exit” ai test del ciclo. Rende chiaro a qualsiasi lettore occasionale che il ciclo potrebbe terminare presto.

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

Soluzione Java 8 Stream :

 List types1 = ... List types2 = ... types1.stream() .flatMap(type1 -> types2.stream().map(type2 -> new Type[]{type1, type2})) .filter(types -> /**some condition**/) .findFirst() .ifPresent(types -> /**do something**/); 

Puoi interrompere da tutti i loop senza utilizzare alcuna etichetta: e le bandiere.

È solo una soluzione complicata.

Qui condizione1 è la condizione che viene utilizzata per interrompere dal ciclo K e J. E condizione2 è la condizione che viene utilizzata per interrompere dal ciclo K, J e I.

Per esempio:

 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"); } } 

Piuttosto per un lungo ho pensato di condividere questo tipo di risposta per questo tipo di domanda.

Di solito, questi casi arrivano nell’ambito di una logica più significativa, diciamo un po ‘di ricerca o manipolazione su alcuni degli oggetti “for” iterati in questione, quindi di solito uso l’approccio funzionale:

 public Object searching(Object[] types) {//or manipulating List typesReferences = new ArrayList(); List typesReferences2 = new ArrayList(); for (Object type : typesReferences) { Object o = getByCriterion(typesReferences2, type); if(o != null) return o; } return null; } private Object getByCriterion(List typesReferences2, Object criterion) { for (Object typeReference : typesReferences2) { if(typeReference.equals(criterion)) { // here comes other complex or specific logic || typeReference.equals(new Object()) return typeReference; } } return null; } 

Principali svantaggi:

  • circa due volte più linee
  • più consumo di cicli di calcolo, il che significa che è più lento dal punto di vista algoritmico
  • più lavoro di battitura

I pro:

  • il rapporto più elevato con la separazione delle preoccupazioni a causa della granularità funzionale
  • il più alto rapporto di riusabilità e controllo della ricerca / manipolazione della logica senza
  • i metodi non sono lunghi, quindi sono più compatti e più facili da comprendere
  • rapporto soggettivamente superiore di leggibilità

Quindi è solo gestire il caso attraverso un approccio diverso.

Fondamentalmente una domanda all’autore di questa domanda: cosa consideri di questo approccio?

Metodo migliore e facile ..

 outerloop: for(int i=0; i<10; i++){ // here we can break Outer loop by break outerloop; innerloop: for(int i=0; i<10; i++){ // here we can break innerloop by break innerloop; } } 

Se è all’interno di una funzione, perché non la restituisci:

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

Approccio piuttosto insolito ma in termini di lunghezza del codice ( non di prestazioni ) questa è la cosa più semplice che si possa fare:

 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 } } 
 boolean broken = false; // declared outside of the loop for efficiency for (Type type : types) { for (Type t : types2) { if (some condition) { broken = true; break; } } if (broken) { break; } } 

Volevo rispondere a questa domanda ma è stato contrassegnato come un duplicato che mi impedisce di pubblicare anche. Quindi pubblicandolo qui!

Se è una nuova implementazione, puoi provare a riscrivere la logica come if-else_if-else statement.

 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 } } 

Altrimenti puoi provare a impostare un flag quando si è verificata questa condizione speciale e controllare il flag in ognuna delle tue condizioni del ciclo.

 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 stai semplicemente trasferendo la logica da un linguaggio di programmazione a Java e vuoi solo far funzionare la cosa, puoi provare ad usare le etichette

Demo per break , continue , label .

Quindi le parole chiave java si break e continue avere un valore predefinito, è il “Ciclo più vicino”, Toady pochi anni dopo l’uso di Java, l’ho appena ottenuto!

Sembra usato raro, ma utile.

 import org.junit.Test; /** * Created by cui on 17-5-4. */ public class BranchLabel { @Test public void test() { System.out.println("testBreak"); testBreak(); System.out.println("testBreakLabel"); testBreakLabel(); System.out.println("testContinue"); testContinue(); System.out.println("testContinueLabel"); testContinueLabel(); } /** testBreak a=0,b=0 a=0,b=1 a=1,b=0 a=1,b=1 a=2,b=0 a=2,b=1 a=3,b=0 a=3,b=1 a=4,b=0 a=4,b=1 */ public void testBreak() { for (int a = 0; a < 5; a++) { for (int b = 0; b < 5; b++) { if (b == 2) { break; } System.out.println("a=" + a + ",b=" + b); } } } /** testContinue a=0,b=0 a=0,b=1 a=0,b=3 a=0,b=4 a=1,b=0 a=1,b=1 a=1,b=3 a=1,b=4 a=2,b=0 a=2,b=1 a=2,b=3 a=2,b=4 a=3,b=0 a=3,b=1 a=3,b=3 a=3,b=4 a=4,b=0 a=4,b=1 a=4,b=3 a=4,b=4 */ public void testContinue() { for (int a = 0; a < 5; a++) { for (int b = 0; b < 5; b++) { if (b == 2) { continue; } System.out.println("a=" + a + ",b=" + b); } } } /** testBreakLabel a=0,b=0,c=0 a=0,b=0,c=1 * */ public void testBreakLabel() { anyName: for (int a = 0; a < 5; a++) { for (int b = 0; b < 5; b++) { for (int c = 0; c < 5; c++) { if (c == 2) { break anyName; } System.out.println("a=" + a + ",b=" + b + ",c=" + c); } } } } /** testContinueLabel a=0,b=0,c=0 a=0,b=0,c=1 a=1,b=0,c=0 a=1,b=0,c=1 a=2,b=0,c=0 a=2,b=0,c=1 a=3,b=0,c=0 a=3,b=0,c=1 a=4,b=0,c=0 a=4,b=0,c=1 */ public void testContinueLabel() { anyName: for (int a = 0; a < 5; a++) { for (int b = 0; b < 5; b++) { for (int c = 0; c < 5; c++) { if (c == 2) { continue anyName; } System.out.println("a=" + a + ",b=" + b + ",c=" + c); } } } } } 

for (int j = 0; j < 5; j++) //inner loop deve essere sostituito con for (int j = 0; j < 5 && !exitloops; j++) .

Qui, in questo caso, i loop nidificati completi devono essere chiusi se la condizione è True . Ma se usiamo exitloops solo per il loop superiore

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

Quindi il ciclo interno continuerà, perché non ci sono flag extra che notificano questo ciclo interno per uscire.

Esempio: se i = 3 e j=2 allora la condizione è false . Ma nella successiva iterazione del ciclo interno j=3 allora la condizione (i*j) diventa 9 che è true ma il ciclo interno continuerà finché j diventerà 5 .

Quindi, deve usare exitloops anche nei loop interni.

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

Come @ 1800 suggerimento di informazioni, utilizzare la condizione che interrompe il ciclo interno come una condizione sul ciclo esterno:

 boolean hasAccess = false; for (int i = 0; i < x && hasAccess == false; i++){ for (int j = 0; j < y; j++){ if (condition == true){ hasAccess = true; break; } } } 

Usa etichette.

 INNER:for(int j = 0; j < numbers.length; j++) { System.out.println("Even number: " + i + ", break from INNER label"); break INNER; } 

Fare riferimento a questo articolo

Un’altra soluzione, menzionata senza esempio (in realtà funziona nel codice 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. } 

Ovviamente BreakLoopException dovrebbe essere interno, privato e accelerato con no-stack-trace:

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

Puoi fare quanto segue:

  1. imposta una variabile locale su false

  2. imposta la variabile true nel primo ciclo, quando desideri interrompere

  3. quindi è ansible verificare nel ciclo esterno, che se la condizione è impostata quindi interrompere anche dal ciclo esterno.

     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 } } 

In alcuni casi, possiamo utilizzare il ciclo while modo efficace qui.

 Random rand = new Random(); // Just an example for (int k = 0; k < 10; ++k) { int count = 0; while (!(rand.nextInt(200) == 100)) { count++; } results[k] = count; } 

Anche la creazione di un flag per il loop esterno e la verifica che dopo ogni esecuzione del ciclo interno può essere la risposta.

Come questo :

 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; } 
 boolean condition = false; for (Type type : types) { for (int i = 0; i < otherTypes.size && !condition; i ++) { condition = true; // if your condition is satisfied } } 

Usa condizione come bandiera per quando hai finito l'elaborazione. Quindi il ciclo interno continua solo quando la condizione non è stata soddisfatta. In entrambi i casi, il ciclo esterno continuerà a funzionare.

Java non ha una funzionalità goto come in C ++. Ma ancora, goto è una parola chiave riservata in Java. Potrebbero implementarlo in futuro. Per la tua domanda, la risposta è che esiste qualcosa chiamato label in Java a cui puoi applicare un’istruzione continue e break . Trova il codice qui sotto:

 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"); } 

Basta usare l’etichetta per rompere i loop interni

 public class Test { public static void main(String[] args) { outerloop: for (int i=0; i < 5; i++) { for (int j=0; j < 5; j++) { if (i * j > 6) { System.out.println("Breaking"); break outerloop; } System.out.println(i + " " + j); } } System.out.println("Done"); } } 

Controlla se il ciclo interno è terminato con un’istruzione if, controllando la variabile del ciclo interno. Potresti anche creare un’altra variabile come un booleano per controllare se il ciclo interno è stato chiuso.

In questo esempio utilizza la variabile del ciclo interno per verificare se è stata chiusa:

 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 } }