迭代器循环中使用break语句

6
假设我的代码如下所示:
for(..)
  for(..)
    for(..){
            break;  //this will break out from the most inner loop OR all 3 iterated loops?
    }
8个回答

29

你的示例只会跳出最内层的循环。然而,使用标记的break语句,可以做到这一点:

outer:
  for(..)
    for(..)
      for(..){
        break outer;  //this will break out from all three loops
      }

4
这是你无论是否喜欢都能够摆脱所有循环的唯一方式 :) - Rakesh Juyal
1
@Raskesh,你可以从一个函数中返回或抛出异常来跳出循环。 - TimW
1
但是为了流程控制而抛出异常也不是很好。 - HeDinges
8
标签比管理布尔值或抛出异常更易读、整洁和高效。如果您无法将代码整理得井井有条并返回一个方法,那么使用标签是最佳解决方案。 - pstanton
1
更加精确地说:如果发生异常状态,必须完全中断,则抛出异常。我认为这很清楚。这是一种技术解决方案,但并不适用于所有情况。对于流程控制:使用标签(或避免嵌套循环,考虑递归)。 - Andreas Dolk
显示剩余2条评论

11

这将只会从内部循环中跳出。您还可以定义一个范围以跳出。更多详情请查看语言规范

没有标签的break语句试图转移控制到最近的外层switch、while、do或for语句,或者立即包含该方法或初始化块的语句;称为break目标的这个语句随后立即正常完成。


4

是的,如果没有标签,它只会中断最内层循环。
不必使用标签,您可以将循环放在一个单独的函数中,并从该函数返回。

class Loop {
    public void loopForXx() {
        untilXx();
    }

    private void untilXx() {
        for()
            for()
                for()
                    if(xx)
                        return; 
    }
}

1
是的,请不要有任何中断或标签! - Fabian Steeg

3

从最内部的循环开始 :)

    int i,j,k;
    for(i = 0; i < 2; i++)
            for(j = 0; j < 2; j++)
                    for(k = 0; k < 2; k++)
                    {
                            printf("%d %d %d\n", i, j, k);
                            break;
                    }

将会产生:

0 0 0
0 1 0
1 0 0
1 1 0

3

1

常常提到我不喜欢打破标签。所以在for循环中,大多数时候我会添加一个布尔变量来简单退出循环..(只有当我想要打破它的时候;))

boolean exit = false;
for (int i = 0; i < 10 && !exit; i++) {
   for (int j = 0; j < 10 && !exit; j++) {
      exit = true;
   }
}

在我看来,这比使用break更优雅。


0

这里有很多人不喜欢标签和跳出。这种技术可以比作使用'goto'语句,即流程控制语句,允许以非标准的方式跳出代码块,忽略前置条件和后置条件。Edsger Dijkstra在ACM通信期刊上发表了一篇著名的文章,日期是1968年3月,“Goto statement considered harmful”(它是一个简短的读物)。

使用TimW建议的从迭代内部返回的同样理由也是不好的。如果我们严格按照创建可读代码、具有可预测的进入点和退出点的原则,那么应该在方法开始时初始化保存返回值(如果有的话)的变量,并仅在方法结束时返回。

当我们使用迭代来执行查找时,这提出了一个挑战。为了避免使用break或return,只能最终得到一个带有常规停止条件和某些布尔变量来指示查找成功的while循环:

boolean targetFound = false;
int i = 0;
while (i < values.size() && ! targetFound ) {

    if (values.get(i).equals(targetValue)) {   
        targetFound  = true;
    }
}
if (!targetFound) {
    // handle lookup failure
} 

好的,这个方法可以运行,但是对我来说有点笨重。首先,我必须引入一个布尔值来检测查找是否成功。其次,我必须在循环后显式地检查targetFound以处理查找失败。

我有时会使用这个解决方案,我认为它更加简洁易读:

lookup: {

    for(Value value : values) {

        if (value.equals(targetValue)) {   
            break lookup;  
        }
    }
    // handle lookup failure here
}

我认为在这里违反规则(无恶意)会导致更好的代码。


你能否编辑第一个示例,以便两个解决方案都使用改进的for循环?这将有助于比较哪个解决方案更容易理解(可读性)。现在这是不公平的竞争。 - Andreas Dolk
不好意思,我不能这样做。这正是我的观点。如果没有break或return语句(或System.exit()调用等),for循环总是会完成,而我假设在找到结果后没有人愿意接受让迭代继续完成的开销。因此,要么通过使用while循环和额外的变量来避免break和return,要么接受在for循环中使用break语句并获得更简洁的代码。 - Adriaan Koster

-2

它将从最内部的循环中退出,

如果你想要从所有循环中退出,你可以定义一个变量并在需要退出时改变其值,然后在每个for循环的开头控制它。


1
管理变量,虽然许多人似乎不喜欢标签,但这样做会更加混乱,并显示了对可用结构的一般误解。 - pstanton

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