我想知道使用break
语句退出循环而不满足循环条件是否是“不好的做法” ?
我对Java和JVM的了解不足,无法知道如何处理循环,因此我想知道我是否通过这样做忽略了一些关键的事情。
这个问题的重点:是否有特定的性能开销?
我想知道使用break
语句退出循环而不满足循环条件是否是“不好的做法” ?
我对Java和JVM的了解不足,无法知道如何处理循环,因此我想知道我是否通过这样做忽略了一些关键的事情。
这个问题的重点:是否有特定的性能开销?
break
与if
周围的代码的整个休息。这就是在其他一些语言中完全遵循“结构化编程”范例的方式。该代码看起来很糟糕。
Answers:
好主啊 有时,可能会在满足整体要求的循环中发生某些事情,而不满足逻辑循环条件。在这种情况下,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,还是循环直到找到该项目并停止?或者说成现实世界;当您找到钥匙时,您一直在寻找吗?
编辑以回应评论
为什么不设置x
来11
打破循环?没有用。我们有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"))
while(x < 10 && item == null)
如果您感觉很花哨,请使用迭代器。
Chris
是出于OP的理解。
x
在循环下面的代码中使用索引怎么办?例如found string at index x
使用break
,就像几乎任何其他语言功能,可以是一个不好的做法,特定的环境,在这里你都清楚地滥用其内。但是,如果没有一些非常重要的习惯用法,就无法对其进行编码,或者至少会导致可读性大大降低。在那些情况下,这break
是要走的路。
换句话说,请勿听取任何笼统,不合格的建议-关于break
或其他任何内容。这不是我第一次看到代码完全消瘦,只是为了从字面上实施“良好实践”。
关于您对性能开销的担心,绝对没有。无论如何,在字节码级别上没有显式的循环构造:所有流控制都是根据条件跳转来实现的。
JLS指定中断是循环的异常终止。但是,仅仅因为它被认为是异常的,并不意味着它没有在许多不同的代码示例,项目,产品,航天飞机等中使用。JVM规范没有指出是否存在性能损失,尽管它是清除代码将在循环后继续执行。
但是,代码可读性可能会受到奇数中断的影响。如果您要在复杂的if语句中插入一个由副作用和奇怪的清除代码包围的中断,可能带有一个带有标签的多级中断(或更糟糕的是,一个又一组的退出条件很奇怪),那么它就不会任何人都容易阅读。
如果您想通过强制迭代变量超出迭代范围或通过引入不必要的直接退出方式来中断循环,则其可读性不如break
。
但是,以空的方式循环额外的时间几乎总是不好的做法,因为它需要额外的迭代,并且可能不清楚。
在我看来,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语句。但是我可以根据自己的经验告诉我们,在较大的循环中可以监视这些中断。(这将我们带到另一个主题,开始将代码分成较小的块)
不,当达到某些所需条件时(例如找到匹配项),跳出循环并不是一个坏习惯。很多时候,您可能要停止迭代,因为您已经达到了想要的目标,没有任何进一步迭代的意义。但是,请务必确保您不会意外丢失某些东西或在不需要时爆发。
如果您中断了循环,这也可以提高性能,而不是即使循环的目的已经完成(即可能已经匹配了所需的记录)也要遍历数千条记录。
范例:
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; } } }
这不是一个坏习惯,但是它会使代码的可读性降低。解决此问题的一种有用的重构方法是将循环移到单独的方法,然后使用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];
}
}
}
当从周围的代码中调用时,可以证明它更具可读性。
如果您开始做这样的事情,那么我会说它开始变得有些奇怪,您最好将其移动到一个单独的方法上,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;
}
}
并更改条件(在上述情况下i
和j
的值),您将使代码确实很难阅读。也可能存在上限(示例中为10)是变量的情况,因此,要想退出循环,更难猜测要设置为哪个值。你当然可以只设置i
和j
为Integer.MAX_VALUE,但我认为你可以看到这个开始变得混乱很快。:)
break
语句转换为return
语句。
goto
,但是在这种情况下特别有用。
在许多常见情况下,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
不仅仅是一个函数调用时。
进一步阅读:循环退出和结构化编程:重新开始辩论
break
并continue
破坏了读者的可读性,尽管它通常很有用。与其说是“ goto”概念,不如说是。
此外,如果您采用了Scala等新语言(受Java和Ocaml等功能性编程语言的启发),您会发现break
并continue
消失了。
特别是在函数式编程中,避免使用这种代码风格:
为什么Scala不支持Break and Continue?
综上所述:break
并且continue
在Java中以命令式风格被广泛使用,但是对于用于实践函数式编程的任何编码器来说,它可能都是..怪异的。