How do I break out of nested loops in Java?
我有一个这样的嵌套循环结构:
1 2 3 4 5 6 7 8 | for (Type type : types) { for (Type t : types2) { if (some condition) { // Do something and break... break; // Breaks out of the inner loop } } } |
现在,我该如何打破这两个循环呢?我已经看过类似的问题,但没有一个特别关注Java。我无法应用这些解决方案,因为大多数人都使用goto。
我不想把内环放在不同的方法中。
我不想重新运行循环。当中断时,循环块的执行就结束了。
像其他的回答者一样,我肯定更喜欢将循环放在不同的方法中,此时您可以返回到完全停止迭代。这个答案只是说明如何满足问题中的需求。
您可以使用带有外循环标签的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
印刷品:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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 |
从技术上来说,正确的答案是给外环贴上标签。在实践中,如果您希望在内部循环中的任何点退出,那么最好将代码外部化为一个方法(如果需要静态方法),然后调用它。
这对可读性是有好处的。
代码会变成这样:
1 2 3 4 5 6 7 8 9 10 11 12 | private static String search(...) { for (Type type : types) { for (Type t : types2) { if (some condition) { // Do something and break... return search; } } } return null; } |
匹配已接受答案的示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
可以在循环周围使用命名块:
1 2 3 4 5 6 7 8 9 10 | search: { for (Type type : types) { for (Type t : types2) { if (some condition) { // Do something and break... break search; } } } } |
我从不使用标签。这似乎是一种不好的习惯。我要做的是:
1 2 3 4 5 6 7 8 9 | 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; } } } |
可以使用标签:
1 2 3 4 5 6 | label1: for (int i = 0;;) { for (int g = 0;;) { break label1; } } |
使用函数:
1 2 3 4 5 6 7 8 9 10 | 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; } } } } |
可以使用临时变量:
1 2 3 4 5 6 7 8 9 10 11 | 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 } } } |
根据您的功能,您还可以从内部循环退出/返回:
1 2 3 4 5 6 7 8 | for (Type type : types) { for (Type t : types2) { if (some condition) { // Do something and break... return; } } } |
如果您不喜欢
1 2 3 4 5 6 7 8 9 10 | 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; } } } |
我需要做一个类似的事情,但我选择不使用增强的for循环来完成它。
1 2 3 4 5 6 7 8 9 10 11 | 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; } } } |
我更喜欢在循环测试中添加一个显式的"exit"。它清楚地表明任何可能提前终止循环的临时读卡器。
1 2 3 4 | boolean earlyExit = false; for(int i = 0 ; i < 10 && !earlyExit; i++) { for(int j = 0 ; i < 10 && !earlyExit; j++) { earlyExit = true; } } |
Java 8 EDCOX1×15解决方案:
1 2 3 4 5 6 7 8 | 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**/); |
通常在这种情况下,它是在更有意义的逻辑范围内出现的,比如说,对问题中的一些迭代的"for"对象进行搜索或操作,因此我通常使用函数方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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; } |
主要缺点:
- 大约两倍多的线条
- 更多的计算周期消耗,这意味着从算法的角度来看,它更慢。
- 更多的打字工作
优点:
- 由于功能粒度的原因,与关注点分离的比率更高
- 更高的可重用性和控制率搜索/操作逻辑
- 这些方法不长,因此更紧凑,更容易理解。
- 主观上较高的可读性比率
所以它只是通过一种不同的方法来处理这个案件。
对于这个问题的作者来说,基本上是一个问题:你认为这个方法怎么样?
您可以在不使用任何标签和标志的情况下从所有循环中断。
这只是个棘手的解决方案。
这里的条件1是用于从循环k和j中断的条件。条件2是用来从循环k,j和i中脱离的条件。
例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 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"); } } |
使用标签。
1 2 3 4 | INNER:for(int j = 0; j < numbers.length; j++) { System.out.println("Even number:" + i +", break from INNER label"); break INNER; } |
参考本文
另一个解决方案,在没有示例的情况下提到(它实际上在prod代码中工作)。
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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. } |
当然,
1 2 3 4 5 6 | private static class BreakLoopException extends Exception { @Override public StackTraceElement[] getStackTrace() { return new StackTraceElement[0]; } } |
相当不寻常的方法,但就代码长度(而不是性能)而言,这是最简单的方法:
1 2 3 4 5 6 | 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 } } |
最好简单的方法。
1 2 3 4 5 6 7 8 9 10 11 | 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; } } |
如果它在某个函数中,为什么不直接返回它:
1 2 3 4 5 6 7 | for (Type type : types) { for (Type t : types2) { if (some condition) { return value; } } } |
在这种情况下,如果条件为
1 | for (int i = 0; i < 5 && !exitloops; i++) //upper loop |
然后内部循环将继续,因为没有额外的标志通知这个内部循环退出。
Example : if
i = 3 andj=2 then condition isfalse . But in next iteration of inner loopj=3 then condition(i*j) become9 which istrue but inner loop will be continue tillj become5 .
因此,它也必须对内部循环使用
1 2 3 4 5 6 7 8 9 10 11 | 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); } } |
Java关键字EDCOX1、10和EDCOX1 9具有默认值。这是"最近的循环",而今天,在使用Java的几年之后,我才得到它!
它似乎很少使用,但很有用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 | 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); } } } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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; } } |
如果这是一个新的实现,您可以尝试像if-else-u if-else语句那样重写逻辑。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 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 } } |
否则,您可以在发生特殊情况时尝试设置标志,并在每个循环条件中检查该标志。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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. } |
在这里!因此,虽然简单的休息不起作用,但可以使用
如果你只是把逻辑从一种编程语言移植到Java,只想让它工作,你可以尝试使用标签。
与@1800信息建议类似,使用中断内部循环的条件作为外部循环的条件:
1 2 3 4 5 6 7 8 9 | 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; } } } |
您可以执行以下操作:
将局部变量设置为
在第一个循环中设置该变量
然后您可以检查外部循环,确认是否设置了条件,然后也从外部循环中断。
1 2 3 4 5 6 7 8 9 10 11 12 | 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 2 3 4 5 6 7 8 9 10 |
甚至为外部循环创建一个标志,并检查在每次执行内部循环之后是否可以得到答案。
这样地:
1 2 3 4 5 6 7 8 9 10 11 12 | 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中分解嵌套循环,通过使用标记的中断,可以中断任何位置的循环嵌套。例1:
1 2 3 4 5 6 7 | loop1: for(int i= 0; i<6; i++){ for(int j=0; j<5; j++){ if(i==3) break loop1; } } |
假设有3个循环,您希望终止循环3:例2:
1 2 3 4 5 6 7 8 9 10 11 | 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 2 3 4 5 6 | boolean condition = false; for (Type type : types) { for (int i = 0; i < otherTypes.size && !condition; i ++) { condition = true; // If your condition is satisfied } } |
当您完成处理时,使用
Java没有像C++那样的Goto特性。但是,EDCOX1×18是Java中的保留关键字。他们将来可能会实施它。对于你的问题,答案是在Java中有一个称为标签的东西,你可以应用EDCOX1×9和EDCOX1×10的语句。查找以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 |
通过检查内部循环的变量,检查内部循环是否使用if语句退出。您还可以创建另一个变量,如布尔值,以检查内部循环是否已退出。
在本例中,它使用内部循环的变量检查是否已退出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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 } } |
你只是用标签来打破内环
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
我觉得使用标签使代码看起来非常像goto语句。这只是一个想法。
相反,在内部
类似的东西
1 2 3 4 5 6 7 8 9 10 11 12 13 | try { // ... for(Object outerForLoop : objectsOuter) { // ... for (Object innerForLoop : objectsInner) { // ... if (isConditionTrue) throw new WrappedException("With some useful message. Probably some logging as well."); } } catch (WrappedException) { // Do something awesome or just don't do anything to swallow the exception. } |
只是一个想法。我更喜欢这段代码,因为当它在生产环境或其他环境中运行时,它为我提供了更好的可写性(就像这个词)。