web-dev-qa-db-fra.com

Comment interrompre plusieurs boucles foreach?

J'ai quatre boucles foreach qui parcourent les collections et font quelque chose en fonction d'une condition.

Voici le code que j'écris maintenant:

boolean breakFlag = false;
String valueFromObj2 = null;
String valueFromObj4 = null;
for(Object1 object1: objects){
  for(Object2 object2: object1){
    // I get some value from object2
    valueFromObj2 = object2.getSomeValue();
    for(Object3 object3 : object2){
      for(Object4 object4: object3){
       // Finally I get some value from Object4.
       valueFromObj4 = object4.getSomeValue();
       // Compare with valueFromObj2 to decide either to break all the foreach loop
       breakFlag = compareTwoVariable(valueFromObj2, valueFromObj4 );
       if(breakFlag){break;}
      } // fourth loop ends here
      if(breakFlag){break;}
    } // third loop ends here
    if(breakFlag){break;}
  } // second loop ends here
  if(breakFlag){break;}
} // first loop ends here

L'objet principal (objets dans le code) provient d'un SDK fournisseur tiers, je ne peux donc rien changer sur cette partie. Je veux demander à la communauté Stack Overflow s'il existe une meilleure approche pour briser les quatre boucles foreach. Ou s'il existe un autre moyen de refactoriser ce code pour le rendre plus lisible et maintenable.

32
royalghost

Utilisez une étiquette sur la boucle la plus externe et incluez cette étiquette dans l'instruction break lorsque vous voulez sauter hors de toutes les boucles. Dans l'exemple ci-dessous, j'ai modifié votre code pour utiliser l'étiquette OUTERMOST:

String valueFromObj2 = null;
String valueFromObj4 = null;
OUTERMOST: for(Object1 object1: objects){
  for(Object2 object2: object1){
    //I get some value from object2
    valueFromObj2 = object2.getSomeValue();
    for(Object3 object3 : object2){
      for(Object4 object4: object3){
        //Finally I get some value from Object4.
        valueFromObj4 = object4.getSomeValue();
        //Compare with valueFromObj2 to decide either to break all the foreach loop
        if( compareTwoVariable(valueFromObj2, valueFromObj4 )) {
          break OUTERMOST;
        }
      }//fourth loop ends here
    }//third loop ends here
  }//second loop ends here
}//first loop ends here
80
Luke Woodward

Extrayez toutes les boucles dans la fonction et utilisez return.

20
Alex Reitbort

Vous pouvez utiliser une instruction break étiquetée. Ce type de pause met fin à une instruction externe

Voir La déclaration break

6
Pierre

Voir le Instructions de branchement Java Tutorial pour la manière la plus simple, en utilisant une étiquette. Vous pouvez étiqueter une ou toutes les boucles for, puis utiliser break ou continue en conjonction avec ces étiquettes.

Une alternative à l'utilisation d'étiquettes consiste à utiliser return à la place. Refactorisez simplement votre code en un appel de méthode pour contourner le besoin d'utiliser des étiquettes.

2
Bill the Lizard

Votre exemple est plutôt générique, il est donc difficile de dire ce qui se passe, mais le code que vous avez fourni me donne une telle odeur de code que je suis obligé de penser qu'il doit y avoir un autre moyen de faire la chose entièrement, très probablement par refactoriser la structure de données réelle en quelque chose de plus significatif.

Quel genre de liste objects est-il? Quelles autres données (très probablement importantes) qu'il contient? Si ce n'est pas trop compliqué, j'apprécierais si vous fournissiez un code plus pertinent car le refactoreur en moi devient tout étourdi juste en voyant cette pile de boucles.

2
Esko

Une façon de casser ou de réduire plusieurs instructions (en fait, empiler des cadres) est de lancer une exception, mais ce n'est pas recommandé car il est très coûteux pour l'exécution de dérouler la pile et cela pourrait conduire à un comportement vraiment difficile à déboguer, (Garde ça en tête).

Sinon, ce que je recommande, réécrivez ce code pour pouvoir sortir de la boucle de manière gracieuse. Si vous ne pouvez pas changer ce code d'une autre manière, eh bien, vous devrez entraîner des exceptions ...

1
John Leidegren

Lancer une exception et l'attraper en dehors des boucles? Utilisez quelque chose qui est "considéré comme dangereux"?

C'est un peu drôle quand l'informatique se peint dans un coin ;-)

0
dwc

La solution la plus simple consiste à placer l'ensemble du processus de recherche dans une méthode et return dès que vous avez une réponse.

Cependant, la forme abstraite de votre exemple de code laisse d'autres possibilités en question. Par exemple, existe-t-il un moyen d '"indexer" une partie du contenu (par exemple en utilisant des instances Map) afin de ne pas avoir à utiliser des boucles de force brute?

0
joel.neely

Outre le fait que Java prend en charge la rupture étiquetée, voir aussi Est-il possible de quitter un for before time en C++, si une condition de fin est atteinte? qui est un question similaire avec d'autres solutions pertinentes.

0
ChrisW