web-dev-qa-db-fra.com

Comment sortir des boucles imbriquées en Java?

J'ai une construction de boucle imbriquée comme ceci:

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

Maintenant, comment puis-je sortir des deux boucles? J'ai examiné des questions similaires, mais aucune ne concerne spécifiquement Java. Je ne pouvais pas appliquer ces solutions parce que les gotos les plus utilisés.

Je ne veux pas mettre la boucle intérieure dans une méthode différente.

Je ne veux pas refaire les boucles. En cassant j'ai fini avec l'exécution du bloc de boucle.

1635
boutta

Comme d’autres répondeurs, j’aurais définitivement préféré de mettre les boucles d’une autre manière, auquel cas vous pouvez simplement revenir pour arrêter complètement d’itérer. Cette réponse montre simplement comment les exigences de la question peuvent être satisfaites.

Vous pouvez utiliser break avec une étiquette pour la boucle externe. Par exemple:

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

Cela imprime:

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
2201
Jon Skeet

Techniquement, la bonne réponse consiste à étiqueter la boucle externe. En pratique, si vous voulez quitter n'importe quel point de la boucle interne, vous feriez mieux d'extérioriser le code dans une méthode (une méthode statique si besoin est) et de l'appeler.

Cela serait rentable pour la lisibilité. 

Le code deviendrait quelque chose comme ça: 

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

Correspondant à l'exemple pour la réponse acceptée:

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

Vous pouvez utiliser un bloc nommé autour des boucles:

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

Je n'utilise jamais d'étiquettes. Cela semble être une mauvaise pratique. Voici ce que je ferais:

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;
        }
    }
}
120
Elle Mundy

Vous pouvez utiliser des étiquettes:

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

Utilisez une fonction:

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

Vous pouvez utiliser une variable temporaire:

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

Selon votre fonction, vous pouvez également quitter/revenir de la boucle interne:

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

Si vous n'aimez pas breaks et gotos, vous pouvez utiliser une boucle for "traditionnelle" à la place de for-in, avec une condition d'abandon supplémentaire:

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

J'avais besoin de faire la même chose, mais j'ai choisi de ne pas utiliser la boucle for améliorée.

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;
        }
    }
}
10
Swifty McSwifterton

Je préfère ajouter une "sortie" explicite aux tests de boucle. Cela indique clairement à tout lecteur occasionnel que la boucle peut se terminer plus tôt.

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

Java 8 Stream solution:

List<Type> types1 = ...
List<Type> types2 = ...

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

Vous pouvez rompre avec toutes les boucles sans utiliser d’étiquette, ni d’indicateur.

C'est juste une solution délicate.

Ici, condition1 est la condition utilisée pour rompre les boucles K et J ..__ et la condition2 est celle utilisée pour rompre les boucles K, J et I.

Par exemple:

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

Habituellement, dans de tels cas, cela relève d'une logique plus significative, par exemple, une recherche ou une manipulation sur certains des objets 'for' en itération en question, c'est pourquoi j'utilise habituellement l'approche fonctionnelle:

public Object searching(Object[] types) { // Or manipulating
    List<Object> typesReferences = new ArrayList<Object>();
    List<Object> typesReferences2 = new ArrayList<Object>();

    for (Object type : typesReferences) {
        Object o = getByCriterion(typesReferences2, type);
        if(o != null) return o;
    }
    return null;
}

private Object getByCriterion(List<Object> 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;
}

Contre majeur:

  • environ deux fois plus de lignes
  • plus de consommation de cycles de calcul, ce qui signifie qu'il est plus lent du point de vue algorithmique
  • plus de travail de dactylographie

Les pros:

  • le rapport plus élevé à la séparation des préoccupations en raison de la granularité fonctionnelle
  • le ratio plus élevé de capacité de réutilisation et de contrôle de la logique de recherche/manipulation sans.
  • les méthodes ne sont pas longues, elles sont donc plus compactes et plus faciles à comprendre
  • taux de lisibilité subjectivement plus élevé

Il s’agit donc simplement de traiter le cas par une approche différente.

Fondamentalement, une question à l'auteur de cette question: que considérez-vous de cette approche?

5
Oleksii Kyslytsyn

Meilleure et facile méthode ..

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;
     }
}
3
Keshav bansal

Si elle se trouve dans une fonction, pourquoi ne pas la renvoyer: 

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

Approche plutôt inhabituelle mais en termes de longueur de code ( pas de performance ), c’est la chose la plus simple que vous puissiez faire:

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

Utilisez des étiquettes.

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

Reportez-vous à cet article

3
Rumesh Eranga

Une autre solution, mentionnée sans exemple (cela fonctionne réellement dans le code 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.
}

Bien entendu, BreakLoopException devrait être interne, privé et accéléré avec no-stack-trace:

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

Démo pour break, continue et label:

Les mots clés Java break et continue ont une valeur par défaut. C'est la "boucle la plus proche" et aujourd'hui, après quelques années d'utilisation de Java, je viens de l'obtenir!

Il semble être utilisé rare, mais 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);
                }
            }
        }
    }
}
2
Bill

for (int j = 0; j < 5; j++) //inner loop doit être remplacé par for (int j = 0; j < 5 && !exitloops; j++).

Ici, dans ce cas, les boucles imbriquées complètes doivent être fermées si la condition est True. Mais si nous utilisons exitloops uniquement vers le haut loop 

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

Ensuite, la boucle interne continuera, car il n'y a pas d'indicateur supplémentaire qui indique à cette boucle interne de quitter. 

Exemple: si i = 3 et j=2, alors la condition est false. Mais lors de la prochaine itération de la boucle interne j=3, la condition (i*j) devient 9, qui est true, mais la boucle interne continue jusqu'à ce que j devienne 5.

Donc, il doit aussi utiliser exitloops pour les boucles internes.

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);
    }
}
2
Vikrant Kashyap

Comme dans la suggestion @ 1800 INFORMATION, utilisez la condition qui casse la boucle interne en tant que condition de la boucle externe:

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;
        }
    }
}
2
mtyson
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;
    }
}
2
Panzercrisis

S'il s'agit d'une nouvelle implémentation, vous pouvez essayer de réécrire la logique comme des instructions 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
    }
}

Sinon, vous pouvez essayer de définir un indicateur lorsque cette condition spéciale est remplie et de rechercher cet indicateur dans chacune de vos conditions de boucle.

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) { // The things below will not be executed
        continue;
    }

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

ICI! Ainsi, même si une simple pause ne fonctionnera pas, vous pouvez le faire en utilisant continue.

Si vous portez simplement la logique d’un langage de programmation à Java et que vous voulez que tout fonctionne, essayez d’utiliser labels .

2
Ravindra HV

Labeled Break Le concept est utilisé pour diviser les boucles imbriquées en Java. En utilisant la commande label, vous pouvez interrompre l’imbrication des boucles à n’importe quel emplacement. Exemple 1:

loop1:
 for(int i= 0; i<6; i++){
    for(int j=0; j<5; j++){
          if(i==3)
            break loop1;
        }
    }

supposons qu'il y ait 3 boucles et que vous vouliez terminer la boucle3: Exemple 2:

loop3: 
for(int i= 0; i<6; i++){
loop2:
  for(int k= 0; k<6; k++){
loop1:
    for(int j=0; j<5; j++){
          if(i==3)
            break loop3;
        }
    }
}
1
Bishal Jaiswal

démo

public static void main(String[] args) {
    outer:
    while (true) {
        while (true) {
            break outer;
        }
    }
}
1
shellhub

Vous pouvez faire ce qui suit:

  1. définir une variable locale sur false

  2. définir cette variable true dans la première boucle, lorsque vous souhaitez interrompre

  3. vous pouvez ensuite vérifier dans la boucle externe que la condition est définie puis la rompre également.

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

Dans certains cas, nous pouvons utiliser la boucle while de manière efficace ici.

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;
}
1
Dharmik Patel

Même créer un drapeau pour la boucle externe et vérifier qu'après chaque exécution de la boucle interne peut être la réponse.

Comme ça:

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

Vérifiez si la boucle interne est sortie avec une instruction if, en vérifiant la variable de la boucle interne. Vous pouvez également créer une autre variable, telle qu'un booléen, pour vérifier si la boucle interne est sortie.

Dans cet exemple, il utilise la variable de la boucle interne pour vérifier si elle a été quittée:

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

Vous venez d'utiliser l'étiquette pour casser les boucles intérieures

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

Voici un exemple où une instruction "break" fait sortir le curseur de la boucle for dès que la condition est remplie.

public class Practice3_FindDuplicateNumber {

    public static void main(String[] args) {
        Integer[] inp = { 2, 3, 4, 3, 3 };
        Integer[] aux_arr = new Integer[inp.length];
        boolean isduplicate = false;
        for (int i = 0; i < aux_arr.length; i++) {

            aux_arr[i] = -1;

        }
        outer: for (int i = 0; i < inp.length; i++) {
            if (aux_arr[inp[i]] == -200) {
                System.out.println("Duplicate Found at index: " + i + " Carrying value: " + inp[i]);
                isduplicate = true;
                break outer;
            } else {
                aux_arr[inp[i]] = -200;
            }
        }

        for (Integer integer : aux_arr) {
            System.out.println(integer);
        }

        if (isduplicate == false) {
            System.out.println("No Duplicates!!!!!");
        } else {
            System.out.println("Duplicates!!!!!");
        }
    }

}
0
Deb

Java n'a pas de fonctionnalité goto comme en C++. Néanmoins, goto est un mot clé réservé en Java. Ils pourraient le mettre en œuvre à l'avenir. Pour répondre à votre question, la réponse est qu’il existe un élément appelé étiquette auquel vous pouvez appliquer une instruction continue et break. Trouvez le code ci-dessous:

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

Utilisez condition comme indicateur lorsque vous avez terminé le traitement. Ensuite, la boucle interne continue uniquement tant que la condition n'a pas été remplie. Dans les deux cas, la boucle externe continuera de fonctionner.

0
astryk