在Java中使用break退出循环是不好的做法吗?[关闭]


79

我想知道使用break语句退出循环而不满足循环条件是否是“不好的做法” ?

我对Java和JVM的了解不足,无法知道如何处理循环,因此我想知道我是否通过这样做忽略了一些关键的事情。

这个问题的重点:是否有特定的性能开销?


13
我不认为这是一个坏习惯,因为“中断”仅用于此目的
Android杀手

19
不好的做法是,即使您可能在5次迭代后退出,也要循环100万次...
assylias 2013年

2
我个人认为这取决于情况,有时使用break可以提高代码的可读性,而且我不认为在这种情况下您可以称其为不好的做法
user902383 2013年

2
这被认为是不好的做法,因为它可能导致许多不希望的情况,例如在创建流而不关闭流之后退出循环/方法。但是,如果您仔细使用它就可以了。
Pshemo

3
基本上,你可以代替任何breakif周围的代码的整个休息。这就是在其他一些语言中完全遵循“结构化编程”范例的方式。该代码看起来很糟糕。
Marko Topolnik

Answers:


133

好主啊 有时,可能会在满足整体要求的循环中发生某些事情,而不满足逻辑循环条件。在这种情况下,break用于阻止您毫无意义地循环。

String item;

for(int x = 0; x < 10; x++)
{
    // Linear search.
    if(array[x].equals("Item I am looking for"))
    {
       //you've found the item. Let's stop.
       item = array[x];
       break; 
    }
}

在此示例中更有意义的是。每次找到后都继续循环到10,还是循环直到找到该项目并停止?或者说成现实世界;当您找到钥匙时,您一直在寻找吗?

编辑以回应评论

为什么不设置x11打破循环?没有用。我们有break!除非您的代码做出的假设x肯定比10以后更大(并且可能不应该这样),否则只使用即可break

为了完整起见进行编辑

肯定还有其他模拟方法break。例如,在循环中为终止条件添加额外的逻辑。说这是无意义的循环或使用break是不公平的。如前所述,while循环通常可以实现类似的功能。例如,按照上面的示例。

while(x < 10 && item == null)
{
    if(array[x].equals("Item I am looking for"))
    {
        item = array[x];
    }

    x++;
}

使用break简单意味着您可以通过for循环实现此功能。这也意味着,只要您希望循环的行为不同,就不必继续在终止逻辑中添加条件。例如。

for(int x = 0; x < 10; x++)
{
   if(array[x].equals("Something that will make me want to cancel"))
   {
       break;
   }
   else if(array[x].equals("Something else that will make me want to cancel"))
   {
       break;
   }
   else if(array[x].equals("This is what I want"))
   {
       item = array[x];
   }
}

而不是while loop带有如下终止条件的:

while(x < 10 && !array[x].equals("Something that will make me want to cancel") && 
                !array[x].equals("Something else that will make me want to cancel"))

OP还询问了类似于将x设置为1000以打破循环的问题
nanofarad 2013年

5
那用while循环而不是休息呢?然后,所有循环完成条件都恰好在循环开始时。while(x < 10 && item == null)如果您感觉很花哨,请使用迭代器。
2013年

@Freiheit:您可以使用它,甚至可以对其进行改进。但是我认为示例Chris是出于OP的理解。
Nandkumar Tekale,2013年

1
@hexafraction:如果我想x在循环下面的代码中使用索引怎么办?例如found string at index x
Nandkumar Tekale 2013年

@NandkumarTekale然后,您需要在外部声明它并完整地打破循环。
nanofarad 2013年

18

使用break,就像几乎任何其他语言功能,可以是一个不好的做法,特定的环境,在这里你都清楚地滥用其内。但是,如果没有一些非常重要的习惯用法,就无法对其进行编码,或者至少会导致可读性大大降低。在那些情况下,这break是要走的路。

换句话说,请勿听取任何笼统,不合格的建议-关于break或其他任何内容。这不是我第一次看到代码完全消瘦,只是为了从字面上实施“良好实践”。

关于您对性能开销的担心,绝对没有。无论如何,在字节码级别上没有显式的循环构造:所有流控制都是根据条件跳转来实现的。


6

JLS指定中断是循环的异常终止。但是,仅仅因为它被认为是异常的,并不意味着它没有在许多不同的代码示例,项目,产品,航天飞机等中使用。JVM规范没有指出是否存在性能损失,尽管它是清除代码将在循环后继续执行。

但是,代码可读性可能会受到奇数中断的影响。如果您要在复杂的if语句中插入一个由副作用和奇怪的清除代码包围的中断,可能带有一个带有标签的多级中断(或更糟糕的是,一个又一组的退出条件很奇怪),那么它就不会任何人都容易阅读。

如果您想通过强制迭代变量超出迭代范围或通过引入不必要的直接退出方式来中断循环,则其可读性不如break

但是,以空的方式循环额外的时间几乎总是不好的做法,因为它需要额外的迭代,并且可能不清楚。


5

在我看来,For当完成固定数量的迭代并且在每次迭代完成之前都不会停止它们时,应该使用循环。在其他情况下,您想更早退出,我更喜欢使用While循环。即使您读了这两个小词,似乎也更合逻辑。一些例子:

for (int i=0;i<10;i++) {
    System.out.println(i);
}

当我快速阅读此代码时,我肯定会知道它会打印出10行,然后继续。

for (int i=0;i<10;i++) {
    if (someCondition) break;
    System.out.println(i);
}

这一点对我来说已经不太清楚了。为什么要先声明要进行10次迭代,然后在循环内添加一些额外条件以尽早停止呢?

我更喜欢以这种方式编写的前面的示例(即使稍微冗长一些,但仅多了一行):

int i=0;
while (i<10 && !someCondition) {
    System.out.println(i);
    i++;
}

每个将阅读此代码的人都将立即看到,有一个额外的条件可能会更早地终止循环。

当然,在很小的循环中,您总是可以讨论每个程序员都会注意到break语句。但是我可以根据自己的经验告诉我们,在较大的循环中可以监视这些中断。(这将我们带到另一个主题,开始将代码分成较小的块)


2
这没有考虑到for或while循环期间达到条件的情况。如果for / while循环触发了一个条件(或者可能在另一个线程上执行了某个条件),那么您可能必须提早休息。您编写的while循环假定您只需要在迭代开始时检查条件即可。
Doc 2013年

我完全同意这种说法。如果您有一个for循环,则意图是将初始化,条件和增量的逻辑放在一个地方。这样省去了在这里和任何地方都可以找到确切情况的麻烦。如果您不知道要循环多少次,那么您正在循环“ while”某事,因此应该是while循环。如果您要循环播放直到某件事,那应该是一阵子。我根本不建议休息是不好的做法,但是有时间和地点可以进行休息。
ThePerson 2014年

4

使用中断循环可能是完全合法的,甚至可能是解决某些问题的唯一方法。

但是,这种不好的声誉来自于这样的事实,即新程序员通常会滥用它,从而导致代码混乱,尤其是通过使用break来停止可能首先在循环条件语句中编写的条件中的循环。


我经常看到这种方式。每当看到一个代码初始化循环变量,用,打开循环while(true),然后break在某种情况下用s时,我都会呕吐。
约翰,

@John有时会被滥用,这没什么不对,有些习语要求while(true)... break。例如,事件循环,其中退出条件并不完全适合该条件,并且您可能希望在中断之前根据信号进行不同的处理。
crasic

4

不,当达到某些所需条件时(例如找到匹配项),跳出循环并不是一个坏习惯。很多时候,您可能要停止迭代,因为您已经达到了想要的目标,没有任何进一步迭代的意义。但是,请务必确保您不会意外丢失某些东西或在不需要时爆发。

如果您中断了循环,这也可以提高性能,而不是即使循环的目的已经完成(即可能已经匹配了所需的记录)也要遍历数千条记录。

范例:

for (int j = 0; j < type.size(); j++) {
        if (condition) {
            // do stuff after which you want 

            break; // stop further iteration
        }

}

您可以使用标记的中断来终止两个循环:search: for (int i = 0; i < s; i++) { for (int j = 0; j < t.size(); j++) { if (condition) { break search; } } }
Michael Konietzka,2013年

是的,我已经知道了。我不小心张贴了它。
Ankur Shanbhag 2013年

2

这不是一个坏习惯,但是它会使代码的可读性降低。解决此问题的一种有用的重构方法是将循环移到单独的方法,然后使用return语句而不是break,例如(从@Chris的答案中摘录):

String item;

for(int x = 0; x < 10; x++)
{
    // Linear search.
    if(array[x].equals("Item I am looking for"))
    {
        //you've found the item. Let's stop.
        item = array[x];
        break; 
    }
}

可以重构(使用extract方法):

public String searchForItem(String itemIamLookingFor)
{
    for(int x = 0; x < 10; x++)
    {
        if(array[x].equals(itemIamLookingFor))
        {
            return array[x];
        }
    }
}

当从周围的代码中调用时,可以证明它更具可读性。


2

如果您开始做这样的事情,那么我会说它开始变得有些奇怪,您最好将其移动到一个单独的方法上,returns该方法将在matchCondition上生成。

boolean matched = false;
for(int i = 0; i < 10; i++) {
    for(int j = 0; j < 10; j++) {
        if(matchedCondition) {
            matched = true;
            break;
        }
    }
    if(matched) {
        break;
    }
}

要详细说明如何清理以上代码,可以进行重构,将代码移至一个函数,returns而不是使用breaks。通常,这更好地处理complex / messy breaks

public boolean  matches()
    for(int i = 0; i < 10; i++) {
        for(int j = 0; j < 10; j++) {
            if(matchedCondition) {
                return true;
            }
        }
    }
    return false;
}

但是对于简单的事情,例如我下面的示例。一定要使用break

for(int i = 0; i < 10; i++) {
    if(wereDoneHere()) { // we're done, break.
        break;
    }
}

并更改条件(在上述情况下ij的值),您将使代码确实很难阅读。也可能存在上限(示例中为10)是变量的情况,因此,要想退出循环,更难猜测要设置为哪个值。你当然可以只设置ij为Integer.MAX_VALUE,但我认为你可以看到这个开始变得混乱很快。:)


“分离方法”重构值得强调。如果您担心一段代码由于某种原因而变得难以阅读,那么将其提取到自己的方法中可能会有所帮助。在此问题的上下文中,它也可以将break语句转换为return语句。
罗素·席尔瓦

1
@RussellSilva谢谢,我将编辑以增加重点。
肯尼·卡森

您可以通过打断标签来简化您的第一种情况。有些人不喜欢它,因为它感觉像a goto,但是在这种情况下特别有用。
Darrel Hoffman

@DarrelHoffman当然可以做到,但是我认为至少在Java中,将其变成单独的方法并返回是处理此问题的“标准”方式。
肯尼·卡森

2

在许多常见情况下,break表达该算法是最自然的方法。它们被称为“半循环”结构;范例是

while (true) {
    item = stream.next();
    if (item == EOF)
        break;
    process(item);
}

如果您不能使用break此功能,则必须重复自己:

item = stream.next();
while (item != EOF) {
    process(item);
    item = stream.next();
}

人们普遍认为情况更糟。

同样,对于continue,有一个常见的模式如下所示:

for (item in list) {
    if (ignore_p(item))
        continue;
    if (trivial_p(item)) {
        process_trivial(item);
        continue;
    }
    process_complicated(item);
}

这通常比使用chained的替代方法更具可读性else if,尤其是当process_complicated不仅仅是一个函数调用时。

进一步阅读:循环退出和结构化编程:重新开始辩论


1

不,这不是一个坏习惯。这是最简单,最有效的方法。


4
但这也可能是最不易读的方式。在大量情况下,这样的一揽子声明通常是错误的。
斯蒂芬·C

这取决于你logic。有时,您想基于某些标志或某些内容异常终止循环。在这种情况下,break是个不错的选择。
2013年

1

尽管使用break并不是坏习惯,并且有很多出色的用法,但它不应该是您所依赖的。中断的几乎所有用法都可以写入循环条件中。当使用实际条件时,代码的可读性要高得多,但是在长时间运行或无限循环的情况下,中断很有意义。如上所示,它们在搜索数据时也很有意义。


1

如果事先知道循环将不得不停止,它可能会提高代码的可读性陈述的条件forwhile`do-while循环。

否则,这就是的确切用例break


1

breakcontinue破坏了读者的可读性,尽管它通常很有用。与其说是“ goto”概念,不如说是。

此外,如果您采用了Scala等新语言(受Java和Ocaml等功能性编程语言的启发),您会发现breakcontinue消失了。

特别是在函数式编程中,避免使用这种代码风格:

为什么Scala不支持Break and Continue?

综上所述:break并且continue在Java中以命令式风格被广泛使用,但是对于用于实践函数式编程的任何编码器来说,它可能都是..怪异的。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.