Comment sortir de boucles imbriquées en Java?
j'ai une construction de boucle imbriquée comme celle-ci:
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 la plupart ont utilisé gotos.
je ne veux pas mettre la boucle interne dans une méthode différente.
mise à jour: Je ne veux pas rediriger les boucles, en cassant je suis fini avec l'exécution du bloc de boucle.
30 réponses
comme les autres answerers, je préférerais certainement mettre la boucle intérieure dans une méthode différente. 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");
}
}
Cette affiche:
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
techniquement, la bonne réponse est d'étiqueter la boucle extérieure. Dans la pratique, si vous voulez sortir à n'importe quel point à l'intérieur d'une boucle interne alors vous feriez mieux d'extériorisation le code dans une méthode (une méthode statique si besoin est) et ensuite l'appeler.
qui paierait 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 de 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);
}
}
}
}
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;
}
}
}
}
Je n'utilise jamais d'étiquettes. Il semble comme 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;
}
}
}
vous pouvez utiliser les étiquettes:
label1:
for (int i = 0;;) {
for (int g = 0;;) {
break label1;
}
}
peut-être avec 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;
}
}
}
}
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 sortir / revenir de la boucle intérieure:
for (Type type : types) {
for (Type t : types2) {
if (some condition) {
// Do something and break...
return;
}
}
}
si vous n'aimez pas break
s et goto
s, vous pouvez utiliser un" traditionnel "pour boucle à la place du for-in, avec une condition supplémentaire d'abandon:
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;
}
}
}
j'avais besoin de faire une chose similaire, mais j'ai choisi de ne pas utiliser la boucle améliorée pour le faire.
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;
}
}
}
je préfère ajouter une" sortie " explicite aux tests de boucle. Il permet à tout lecteur occasionnel que la boucle peut se terminer tôt.
boolean earlyExit = false;
for(int i = 0 ; i < 10 && !earlyExit; i++) {
for(int j = 0 ; i < 10 && !earlyExit; j++) { earlyExit = true; }
}
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**/);
vous pouvez casser de toutes les boucles sans utiliser aucune étiquette: et des drapeaux.
c'est juste une solution délicate.
Ici condition1 est la condition qui est utilisé pour casser de la boucle K et J. Et condition2 est la condition qui est utilisé pour casser de la boucle 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");
}
}
plutôt pendant longtemps je pensais à partager ce type de réponse pour ce type de question.
habituellement, de tels cas entrent dans la portée d'une logique plus significative, disons une recherche ou une manipulation sur certains des 'pour'itérés' -objets en question, donc 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;
}
Grands inconvénients:
- environ deux fois plus de lignes
- plus de consommation de cycles de calcul, ce qui signifie qu'il est plus lent d'un point de vue algorithmique
- plus de travaux de Dactylographie
Les pros:
- la plus élevée par rapport à la séparation des préoccupations en raison de la fonctionnelle de la granularité
- le rapport plus élevé de réutilisation et de contrôle de recherche / manipulation de logique sans
- les méthodes ne sont pas longues, donc elles sont plus compactes et plus faciles à comprendre
- subjectivement ratio plus élevé de la lisibilité
donc il s'agit simplement de gérer le cas par une approche différente.
Essentiellement d'une question à l'auteur de cette question: que pensez-vous de cette approche?
si elle est à l'intérieur d'une fonction, pourquoi ne pas la retourner:
for (Type type : types) {
for (Type t : types2) {
if (some condition) {
return value;
}
}
}
meilleure méthode et 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;
}
}
approche plutôt inhabituelle mais en termes de longueur de code ( pas de performance ) c'est la chose la plus facile que vous pourriez 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
}
}
Utiliser Des Étiquettes.
INNER:for(int j = 0; j < numbers.length; j++) {
System.out.println("Even number: " + i + ", break from INNER label");
break INNER;
}
Consultez cet article
une autre solution, mentionnée sans exemple (elle fonctionne en fait 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 sûr BreakLoopException
doit ê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];
}
}
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;
}
}
je voulais répondre cette question mais a été marqué comme un double qui m'empêche de poster aussi. Alors affichez-le ici à la place !
si c'est une nouvelle implémentation, vous pouvez essayer de réécrire la logique comme si-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 mettre un drapeau quand cette condition spéciale a produit et vérifier que le drapeau dans chaque votre boucle conditions.
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.
si vous transférez simplement la logique d'un langage de programmation À java et que vous voulez juste faire fonctionner la chose, vous pouvez essayer d'utiliser étiquettes
démo pour break
, continue
, label
.
donc les mots clés java break
et continue
ont une valeur par défaut, c'est la" boucle la plus proche", déjà quelques années après L'utilisation de Java, je viens de l'obtenir !
ça semble 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);
}
}
}
}
}
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 exit si la condition est True
. Mais si nous utilisons exitloops
seulement vers le haut loop
for (int i = 0; i < 5 && !exitloops; i++) //upper loop
alors la boucle intérieure continuera, parce qu'il n'y a pas de drapeau supplémentaire qui avertit cette boucle intérieure de sortir.
exemple: si
i = 3
etj=2
alors la condition estfalse
. Mais dans la prochaine itération de boucle internej=3
alors condition(i*j)
devenir9
qui esttrue
mais boucle interne sera continue jusqu'àj
devenir5
.
ainsi, il doit utiliser exitloops
aux boucles intérieures aussi.
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);
}
}
comme @1800 suggestion D'INFORMATION, utilisez la condition qui casse la boucle interne comme condition sur 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;
}
}
}
vous pouvez faire ce qui suit:
-
fixe une variable locale à
false
-
définissez cette variable
true
dans la première boucle, quand vous voulez casser -
ensuite, vous pouvez vérifier dans la boucle extérieure, que si la condition est réglée puis briser de la boucle extérieure aussi bien.
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 } }
pour certains cas, nous pouvons utiliser efficacement la boucle while
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;
}
même en créant un drapeau pour boucle extérieure et en vérifiant qu'après chaque exécution de boucle intérieure peut être la réponse.
comme ceci:
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
}
}
utiliser la condition comme un drapeau pour quand vous avez terminé le traitement. Ensuite, la boucle interne seulement continue tant que la condition n'est pas remplie. Quoi qu'il en soit, la boucle extérieure va continuer.
Java n'a pas de fonctionnalité goto comme il en existe en C++. Mais tout de même, goto
est un mot-clé réservé en Java. Ils pourraient la mettre en œuvre à l'avenir. Pour votre question, la réponse est qu'il y a quelque chose appelé étiquette en Java à laquelle vous pouvez appliquer une déclaration continue
et break
. Trouver 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");
}
il suffit d'utiliser l'étiquette pour briser 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");
}
}
vérifiez si la boucle intérieure est sortie avec une instruction if, en cochant la variable de la boucle intérieure. Vous pouvez également créer une autre variable comme un booléen pour vérifier si la boucle interne est terminée.
dans cet exemple, il utilise la variable de la boucle intérieure pour vérifier si elle a été retiré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
}
}