如何在Java中释放嵌套循环?

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。

我不想把内环放在不同的方法中。

我不想重新运行循环。当中断时,循环块的执行就结束了。


像其他的回答者一样,我肯定更喜欢将循环放在不同的方法中,此时您可以返回到完全停止迭代。这个答案只是说明如何满足问题中的需求。

您可以使用带有外循环标签的break。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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");
    }
}

印刷品:

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

  • 这确实会直接跳到循环之后。试试看!是的,标签在循环之前,但这是因为它标记的是循环,而不是您要退出到的位置。(您也可以继续使用标签。)
  • Perl也允许使用它自己的标签系统。我认为很多语言都是这样的——它几乎不让我惊讶它是在Java中。
  • @埃文——这一说法显然是正确的——用语言来保证它是正确的。但是Java并没有实现这个承诺。如果一种语言与你的假设相冲突,很可能是你的假设有问题。在这种情况下,我认为你仍然是部分正确的——这一点对许多从未听说过(或忘记过)那种形式的break的人来说是最不令人惊讶的。即便如此,例外也是另一个众所周知的例外(抱歉)。但如果不明显的话,我还是会对此感到不高兴(小循环,如果标签/断纸仍然不够明显的话,警告注释)。
  • @Boutta-Ada有一个用exit when ;语句拼写的中断样式,它有一个goto,因此您可以将标签放在循环的任一端。不过,iirc,gotoexit版本更不受欢迎。即使对于江户十一〔四〕来说,有些人也会用一根很大的棍子打你,因为你用的是"隐藏的哥特",但如果你用的是明目张胆的哥特……
  • 一个乔恩·斯基特的回答是,我不太喜欢,因为我不想通过这样一个带有所有标签的代码。但由于该语言允许,所以被否决了。
  • jonskeet或@bgr为什么标签破损不好?或者为什么你更喜欢另一种方式?
  • @JWILEY:我通常发现从代码中间返回的方法更容易读取。
  • @ JWiley。这里也一样;更容易阅读:当你"点击"返回时,你可以停止阅读-更容易维护:当修复返回之前的东西时,你不必担心循环之外的副作用。imho,快速返回通常会导致更紧凑、更简单的代码。
  • 在Dijkstra的"Goto被认为是有害的"论文中,他特别反对的是标签,而不是Goto。他观察到,错误的数量似乎随着程序中标签的数量增加而增加,标签和goto使程序难以分析。
  • 什么是outerloop?没有类型?甚至我也试着做同样的语法错误!
  • @Muhammadbabar:outerloop是一个标签。我不知道您尝试了什么代码,但我的答案中的代码可以编译并运行得很好。
  • 这种模式是否适用于在作为循环一部分的switch-case语句中突破循环?
  • @布鲁斯:我想是的,但我建议你试试看。
  • @二胡,关于标签,我认为"中断"或"继续"比"去"更容易阅读,因为你可以中断或继续的地方很少,而且很容易找到。
  • @Minhaskamal:请停止编辑,不要无缘无故地用粗体输入"edit",并引用输出片段。你的建议编辑不清楚,明显与我的预期缩进等冲突。
  • "break outerloop"="转到"语句。乌尔赫!我使用布尔值作为显式触发器来终止for语句中的循环,当我有嵌套的循环时,从内部循环中退出一个单点,然后在每个循环外部进行进一步的测试,以实现相同的结果,但是imho更好地实现可维护性。各自为政……
  • 还有这种操作?从没听说过,嗯…每天学一点……
  • 这是一个可读性的问题。我认为标记的break是完全可读的,它明确地声明了它要离开的块,所以对我来说,它比未标记的break更清晰。尽管如此,如果嵌套循环满足某种可以用方法名表示的目的(并且不需要传递十几个参数),那么就引入该方法。但我肯定更喜欢带标签break的嵌套循环,而不是名为"loop"的方法。
  • 我在我的IDE中安装了sonarlint插件,在使用带标签的break时,sonarlint将其作为major codeSmell提供,当我查看提供的描述时,它说Labels are not commonly used in Java, and many developers do not understand how they work。原因是否合理?
  • @Nisargpatil:虽然我不认为这是一种"主要的代码味道",但是推理似乎是合理的。不过,根据我答案的开头,我宁愿把它放在一个单独的方法中。
  • 也许您的意思是"将两个循环都放在不同的方法中(或者在需要continue而不是break的情况下只放在外循环的主体中)"?
  • @约翰:9年后很难确切知道我的意思,但我怀疑你是对的。将编辑。
  • @尼沙尔帕蒂尔只是因为它在声纳林不会使它成为一个代码气味。这仅仅意味着有一个开发者把这个添加到了Sonarlint中,并且个人渴望抓取,而且它充满了只有在被滥用时才有意义的这些规则,或者因为一些开发者有一个针对它们的个人仇恨运动。贴有标签的休息和继续是一个非常优雅的方式来描述你想做什么。
  • 与许多评论家不同,我发现这个结构没有任何问题。它通常比标记变量更清晰。我认为Dijkstra对标签扩散的抱怨并不是问题所在。有了60年代的经典标签和Goto,标签的出现意味着控制几乎可以从任何方式到达那里。这种标签不是跳转目标,它只是命名一个语句。不过,我发现"break foo"在可读性方面有点奇怪;bliss对同一构造使用了"leave foo",从语言上讲,这更有意义:我们将离开名为"foo"的语句。


从技术上来说,正确的答案是给外环贴上标签。在实践中,如果您希望在内部循环中的任何点退出,那么最好将代码外部化为一个方法(如果需要静态方法),然后调用它。

这对可读性是有好处的。

代码会变成这样:

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

  • 有时,您使用几个内部循环之外的局部变量,将它们全部传入可能会感到笨拙。
  • 那么,这个解决方案应该如何打印出"完成"的答案呢?
  • @johndoe调用它,然后打印system.out.println("done");在搜索方法中尝试finally也是一个选项。
  • 我想这是更好的练习,但是如果你想继续而不是打破呢?标签支持同样好(或不好!)但我不知道如何将这个逻辑转换为continue。
  • @如果要继续而不是中断,请将外部循环移出loop方法,然后从方法返回以继续。


可以在循环周围使用命名块:

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

  • 不需要创建新块来使用标签。
  • 不,但它使意图更加清晰。请参阅对已接受答案的第一条评论。
  • 它实际上不是一个命名块,在标签之后,您可以编写任何Java表达式作为无标签,EDCOX1×5是否命名为条件?:)
  • 这种结构比直接标记for有很大的优势。您可以在最后一个}之前添加代码,只有在条件从未满足时才会执行该代码。
  • 它是一个命名块,而不是一个命名循环。如果循环名为search,则不能在该循环中使用"continue search";这是完全合法的语法。你可以打破它,但你不能继续。
  • 弗洛里安是完全正确的。break真的会把你吐出来。如果循环完成,你会有一些额外的事情要做,而如果循环中断,你会有1次执行跳过的事情。如果你打破这个障碍,你可以用一块石头杀死这两只鸟,这可能实际上是一些合理的可读性。对于@lavlozmerrill问题,可以标记并中断if语句,也可以在else中中断标记的if。但是,如果将语句标记为if执行,则只能在if中中断该语句。


我从不使用标签。这似乎是一种不好的习惯。我要做的是:

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

  • 这不是应该是&& !finished而不是|| !finished吗?那么为什么要使用break,而不使用&& !finished作为内环呢?
  • 我使用break可以任意退出循环。如果在该if块之后有代码,则可以在执行之前break。但你说得对,&&。修理它。
  • 不错的解决方案!如果出于某种原因把它放在一个额外的函数中是不可取的,这就是我在实践中应该做的。
  • @福特加:那你也不要用开关箱了!使用break并不是一个坏习惯,只要它是用常识!
  • 如果在内部循环之后有一些逻辑,就存在一个潜在的问题…只有当新的迭代开始时,外部循环才会中断…
  • 我不明白为什么要这样做。使用代码的人应该能够使用语言的所有特性。我明白,编写别人可以理解的代码很重要,但这不是通过限制语言提供的官方工具的使用,并为相同的功能找到解决方法。或者你说"坏习惯"是指别的什么?
  • @codepleb有时使用内置语言特性是一种糟糕的实践。例如,即使语言提供了"assert"关键字,也不应将其用于生产代码验证,因为可以在JVM中关闭断言检查。或者您通常应该如何使用日志框架而不是System.Out来处理除简单命令行工具之外的其他任何事情。
  • 如果是foreach外循环,您会怎么做?


可以使用标签:

1
2
3
4
5
6
label1:
for (int i = 0;;) {
    for (int g = 0;;) {
      break label1;
    }
}

  • 不公平,这个答案也是正确的。但只有55票赞成。
  • 阅读起来也简单多了。
  • 我要一个+1。简而言之,回答问题。不能因为你同时回答而被指控重复现有答案。


使用函数:

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

  • 我觉得这样有点杂乱。
  • 笨手笨脚,容易出错。
  • 每次循环都要进行额外的条件检查?不用了,谢谢。


如果您不喜欢breakgoto,您可以使用"传统"for循环,而不是for-in,带有额外的中止条件:

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

  • 不适用于前臂环。
  • @约翰姆克兰,你在一个9岁以上的问题的很多答案上都写了这个,因为…?


我需要做一个类似的事情,但我选择不使用增强的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;
        }
    }
}

  • 我觉得在条件被破坏后迭代所有项并不酷。因此,我将在其他情况下添加一个中断。
  • @我不知道你是怎么得出这个结论的。一旦条件为真,两个循环都将退出。
  • 好吧,我没有得到处理"s"变量的部分,但是我发现这种风格很糟糕,因为s代表的是大小。那么我更喜欢ddyer给出的带有显式变量的答案:stackoverflow.com/a/25124317/15108
  • @关于你可以把s改成比i低的值,或者把i改成大于或等于s的值,这两种方法都应该奏效。你改变s是对的,因为它可以在以后的其他地方使用,但是改变i不会造成伤害,只会确保第一个for不会继续循环。


我更喜欢在循环测试中添加一个显式的"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**/);

  • 这个问题是在09年被问到的…
  • @tvde1对其他用户仍然有用,因此欢迎使用新的方法和解决方案。


通常在这种情况下,它是在更有意义的逻辑范围内出现的,比如说,对问题中的一些迭代的"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");
    }
}

  • 对于每个循环,我如何使用它?;)
  • 如果您有一个更复杂的循环条件,比如list.size()>5,这就不起作用。而且这真的只是一个黑客。很难读懂,也很难练习!
  • 这很容易出错。假设您将内环改为(int k = 0; k < 10; k++),并且没有将所有k = 9都改为k = 10。你可能会进入一个无限循环。


使用标签。

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

当然,BreakLoopException应该是内部的、私有的和加速的,没有堆栈跟踪:

1
2
3
4
5
6
private static class BreakLoopException extends Exception {
    @Override
    public StackTraceElement[] getStackTrace() {
        return new StackTraceElement[0];
    }
}

  • 事实上,在一个获得-23票的答案中提到…stackoverflow.com/a/886980/2516301。它可以完成这项工作,但它是一个非常糟糕的编程实践…
  • 的确。然而,我看到了这样的遗留代码——4级嵌套循环,有几个中断条件。它更易于阅读,但有例外,而不是内联代码。-23票多数是情绪化评分,但是的-这种方法应该谨慎使用。
  • 如果它被分解成一个单独的函数调用并返回一个中心,那么它的可读性会更高。通常通过一点重构就可以做得更好,所以作为一个独立的(通常是可重用的)函数是有意义的。


相当不寻常的方法,但就代码长度(而不是性能)而言,这是最简单的方法:

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

  • 这些破坏的例子并不是很有帮助,因为即使没有标签,它们也会在同一点上破坏。还有,拥有可以实际执行的代码总是很好的,这与您的代码不同,因为无法访问innerloop。
  • 我要打同样的东西。在这种情况下,标签有些无用。


如果它在某个函数中,为什么不直接返回它:

1
2
3
4
5
6
7
for (Type type : types) {
    for (Type t : types2) {
         if (some condition) {
            return value;
         }
    }
}

  • 我喜欢这种式样。它经常导致我将循环分解成一个单独的函数。这样做之后,我的代码总是更好,因此我非常喜欢这个答案。


for (int j = 0; j < 5; j++) //inner loop应替换为for (int j = 0; j < 5 && !exitloops; j++)

在这种情况下,如果条件为True,则应退出完整的嵌套循环。但是,如果我们只对上面的loop使用exitloops

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

然后内部循环将继续,因为没有额外的标志通知这个内部循环退出。

Example : if i = 3 and j=2 then condition is false. But in next iteration of inner loop j=3 then condition (i*j) become 9 which is true but inner loop will be continue till j become 5.

因此,它也必须对内部循环使用exitloops

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


breakcontinuelabel的演示:

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

在这里!因此,虽然简单的休息不起作用,但可以使用continue来工作。

如果你只是把逻辑从一种编程语言移植到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;
        }
    }
}

您可以执行以下操作:

  • 将局部变量设置为false

  • 在第一个循环中设置该变量True,当您想要中断时

  • 然后您可以检查外部循环,确认是否设置了条件,然后也从外部循环中断。

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

  • 在某些情况下,我们可以在这里有效地使用while循环。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    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
    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
        }
    }

    当您完成处理时,使用condition作为标记。然后,内部循环仅在未满足条件时继续。不管怎样,外环都将保持在Chuggin'上。


    Java没有像C++那样的Goto特性。但是,EDCOX1×18是Java中的保留关键字。他们将来可能会实施它。对于你的问题,答案是在Java中有一个称为标签的东西,你可以应用EDCOX1×9和EDCOX1×10的语句。查找以下代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    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");
    }

    通过检查内部循环的变量,检查内部循环是否使用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
    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");
    }
    }

    • 与公认的答案有什么区别?


    我觉得使用标签使代码看起来非常像goto语句。这只是一个想法。

    相反,在内部for循环中抛出异常,并用一个try-catch块封装两个for循环。

    类似的东西

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

    只是一个想法。我更喜欢这段代码,因为当它在生产环境或其他环境中运行时,它为我提供了更好的可写性(就像这个词)。

    • 对控制流使用异常并不完全是最佳实践。所以,不,这是没有选择的。
    • @你为什么这么想?
    • 大量的阅读和一些广受信任的人的意见,如鲍勃·奥德·马丁·福勒叔叔。