如何在Java中打破嵌套循环?

2068

我有一个像这样嵌套的循环结构:

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

现在我该如何跳出这两个循环?我查看了类似的问题,但没有涉及到Java。我无法应用这些解决方案,因为大多数使用goto语句。
我不想将内部循环放在不同的方法中。
我不想返回循环。当我跳出时,我已经完成了循环块的执行。
37个回答

2731

和其他答案一样,我肯定会更喜欢将循环放在一个不同的方法中,在那时,你可以直接返回以完全停止迭代。这个答案只是展示了如何满足问题中的要求。

你可以使用一个带有外部循环标签的break。例如:

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

315
尝试一下!这会直接跳到循环后面。是的,标签在循环之前,但这是因为它给循环打标签,而不是你想要退出的位置。(你也可以用标签继续执行。) - Jon Skeet
将其分解为不同的方法只有在状态很小或以可通过引用传递的形式保持时才是一种优势。如果循环所引用/操作的状态较大,则需要一种优雅的方法来跳出/继续循环。 - Graeme Gill
2
直到我看到这个答案,我才知道Java有标记循环的概念 ¯_(ツ)_/¯ - iCantC

437

从技术上讲,正确的答案是给外部循环打标签。实际上,如果你想在内部循环的任何点退出,最好将代码外部化为一个方法(如果需要,可以使用静态方法),然后调用它。

这样做会提高可读性。

代码将变成以下形式:

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

按照已接受答案的示例进行匹配:

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

35
有时候你会在内部循环之外使用几个局部变量,将它们全部传入可能感觉笨重。 - Haoest

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

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

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

44
使用标签不需要创建新的区块。 - Jon Skeet
94
不,但是它可以使意图更清晰。请参见已接受答案的第一条评论。 - Bombe

154

我从不使用标签。这似乎是一个不好的习惯。以下是我的做法:

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

通过设置标志变量,我们可以轻松控制任意数量的循环执行。我们只需要在循环条件语句中检查此标志值,就像在主循环中所做的那样:i < 5 && !finished。

1
所以你允许额外的循环只是为了不必标记“for”吗? - undefined

127

你可以使用标签:

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

44

使用一个函数:

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

24

您可以使用一个临时变量:

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

根据您的功能,您还可以从内部循环中退出或返回:

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

21

当您需要从多个循环中退出时,仅使用“break”关键字不是适当的方式。 您可以从立即循环中退出, 无论您的语句被包围了多少个循环。 您可以使用带有标签的“break”! 这里我使用了标签“abc” 您可以在Java中的任何函数内编写以下代码以退出最外层循环。

此代码显示如何退出最外层循环

 abc: 
    for (int i = 0; i < 10; i++) { 
        for (int j = 0; j < 10; j++) { 
           for (int k = 0; k < 10; k++) { 
              if (k == 1){
                 break abc;
              } 
        } 
    } 
}

你也可以使用break语句在嵌套循环中退出任何一个循环。

    for (int i = 0; i < 10; i++) { 
       abc:for (int j = 0; j < 10; j++) { 
           for (int k = 0; k < 10; k++) { 
              if (k == 1){
                 break abc;
              } 
        } 
    } 
}
以下代码展示了从最内层循环中退出的例子。换言之,在执行以下代码后,您处于“k”变量的循环之外,仍然在“j”和“i”变量的循环内部。
Translated text: 以下代码展示了从最内层循环中退出的例子。换言之,在执行以下代码后,您处于“k”变量的循环之外,仍然在“j”和“i”变量的循环内部。
    for (int i = 0; i < 10; i++) { 
        for (int j = 0; j < 10; j++) { 
           for (int k = 0; k < 10; k++) { 
              if (k == 1){
                 break;
              } 
        } 
    } 
}

17
如果您不喜欢breakgoto,可以使用“传统”的for循环代替for-in,加上一个额外的中止条件:
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;
        }
    }
}

3
不适合使用 foreach 循环。 - John McClane
3
你为什么要在一个九年历史的问题下面的许多答案上发这个垃圾信息? - Quintec

13

我需要做类似的事情,但我选择不使用增强型for循环来完成它。

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

我觉得在条件被打破后迭代所有的项目并不酷。因此,我会在else语句中添加一个break。 - boutta
@boutta 我不确定你是如何得出这个结论的。一旦条件为真,两个循环都会退出。 - Swifty McSwifterton
好的,我没有理解关于“s”变量操作的部分。但我认为这种做法不太好,因为“s”代表大小。所以我更喜欢ddyer的答案,使用显式变量:https://dev59.com/5nNA5IYBdhLWcg3wn_bD#25124317 - boutta
@boutta 你可以将s更改为小于i的值,或将i更改为大于或等于s的值,两者都可以解决问题。你关于更改s的想法是正确的,因为它可能会在后面的代码中使用,但更改i不会有任何影响,只是确保第一个for循环不会继续执行。 - Zsolti

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接