如何打破 Java 中的嵌套循环?
Posted
技术标签:
【中文标题】如何打破 Java 中的嵌套循环?【英文标题】:How do I break out of nested loops in Java? 【发布时间】:2009-05-20 09:07:43 【问题描述】:我有一个这样的嵌套循环结构:
for (Type type : types)
for (Type t : types2)
if (some condition)
// Do something and break...
break; // Breaks out of the inner loop
现在我怎样才能打破这两个循环?我看过类似的问题,但没有一个特别关注 Java。我无法应用这些解决方案,因为大多数使用 goto。
我不想将内部循环放在不同的方法中。
我不想返回循环。中断时,我完成了循环块的执行。
【问题讨论】:
【参考方案1】:像其他回答者一样,我肯定更喜欢将循环放在不同的方法中,此时您可以返回以完全停止迭代。这个答案只是说明了如何满足问题中的要求。
您可以将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
【讨论】:
这个确实直接跳转到循环之后。尝试一下!是的,标签出现在循环之前,但那是因为它标记了循环,而不是您想要退出的地方。 (您也可以继续使用标签。)【参考方案2】:从技术上讲,正确的答案是标记外循环。实际上,如果您想在内部循环中的任何点退出,那么最好将代码外部化为方法(如果需要,可以使用静态方法)然后调用它。
这将为可读性带来回报。
代码会变成这样:
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);
【讨论】:
有时您会使用多个位于内部循环之外的局部变量,将它们全部传入会感觉很笨重。【参考方案3】:您可以在循环周围使用命名块:
search:
for (Type type : types)
for (Type t : types2)
if (some condition)
// Do something and break...
break search;
【讨论】:
您无需创建新块即可使用标签。 不,但它使意图更加清晰。请参阅已接受答案的第一条评论。【参考方案4】:我从不使用标签。进入这似乎是一种不好的做法。这就是我要做的:
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;
【讨论】:
【参考方案5】:你可以使用标签:
label1:
for (int i = 0;;)
for (int g = 0;;)
break label1;
【讨论】:
【参考方案6】:使用函数:
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;
【讨论】:
【参考方案7】:您可以使用临时变量:
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;
【讨论】:
【参考方案8】:如果您不喜欢 break
s 和 goto
s,您可以使用“传统”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;
【讨论】:
不适合 foreach 循环。 @JohnMcClane 而且你在一个 9 岁以上的问题的许多答案上发送垃圾邮件是因为......?【参考方案9】:我需要做类似的事情,但我选择不使用增强的 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 情况下添加一个中断。 @boutta 我不确定你是如何得出这个结论的。一旦条件为真,两个循环都将退出。 好的,我没有得到操纵 's' 变量的部分。但我发现那种不好的风格,因为 s 代表大小。然后我更喜欢来自 ddyer 的带有显式变量的答案:***.com/a/25124317/15108 @boutta 您可以将s
更改为小于i
的值或将i
更改为大于或等于s
的值,两者都可以解决问题。更改s
是对的,因为以后可以在其他地方使用它,但是更改i
不会造成伤害,只会确保第一个for
不会继续循环。【参考方案10】:
我更喜欢在循环测试中添加一个明确的“退出”。它清楚地表明 任何不经意的读者都知道循环可能会提前终止。
boolean earlyExit = false;
for(int i = 0 ; i < 10 && !earlyExit; i++)
for(int j = 0 ; i < 10 && !earlyExit; j++) earlyExit = true;
【讨论】:
【参考方案11】:当您需要退出多个循环时,单独使用“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'变量的循环内。
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;
【讨论】:
【参考方案12】:Java 8 Stream
解决方案:
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**/);
【讨论】:
@Tvde1 并且对其他用户仍然有用,所以总是欢迎新的方法和解决方案【参考方案13】:带标签的break概念用于打破java中的嵌套循环,通过使用带标签的break,您可以在任何位置打破循环的嵌套。 示例 1:
loop1:
for(int i= 0; i<6; i++)
for(int j=0; j<5; j++)
if(i==3)
break loop1;
假设有 3 个循环并且您想终止循环 3: 示例 2:
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;
【讨论】:
【参考方案14】:通常在这种情况下,它会出现在更有意义的逻辑范围内,比如对一些有问题的迭代“for”对象进行一些搜索或操作,所以我通常使用函数式方法:
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;
主要缺点:
大约多行两倍 更多的计算周期消耗,这意味着从算法的角度来看它更慢 更多打字工作优点:
由于功能粒度,关注点分离的比率更高 更高的复用率和控制率 搜索/操作逻辑没有 方法不长,更紧凑,更容易理解 更高的可读性比率所以它只是通过不同的方法处理此案。
基本上是向这个问题的作者提出的一个问题:您如何看待这种方法?
【讨论】:
【参考方案15】:您可以在不使用任何标签:和标志的情况下中断所有循环。
这只是一个棘手的解决方案。
这里的 condition1 是用于从循环 K 和 J 中中断的条件。 而 condition2 是用于从循环 K 、 J 和 I 中中断的条件。
例如:
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");
【讨论】:
如何将它与 for-each 循环一起使用? ;) 如果您有更复杂的循环条件,例如 list.size()>5,这将不起作用。而且它真的只是一个黑客。很难阅读和不好的做法! 容易出错。想象一下,您将内部循环更改为(int k = 0; k < 10; k++)
,并且您没有将所有k = 9
修复为k = 10
。你可能会陷入无限循环。【参考方案16】:
使用标签。
INNER:for(int j = 0; j < numbers.length; j++)
System.out.println("Even number: " + i + ", break from INNER label");
break INNER;
参考this article
【讨论】:
【参考方案17】:最简单的方法..
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;
【讨论】:
这些中断示例在恕我直言不是很有帮助,因为即使没有标签,它们也会在同一点中断。此外,拥有可以实际执行的代码总是很好的,但您的代码并非如此,因为永远无法到达内部循环.. 我打算输入同样的内容。在这种情况下,标签有些用处。【参考方案18】:演示
public static void main(String[] args)
outer:
while (true)
while (true)
break outer;
【讨论】:
【参考方案19】: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;
【讨论】:
【参考方案20】:如果它在某个函数中,为什么不直接返回它:
for (Type type : types)
for (Type t : types2)
if (some condition)
return value;
【讨论】:
我更喜欢这种模式。它经常导致我将循环分解为一个单独的函数。这样做后我的代码总是更好,因此我非常喜欢这个答案。【参考方案21】:相当不寻常的方法,但就代码长度(不是性能)而言,这是您可以做的最简单的事情:
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
【讨论】:
【参考方案22】:另一种解决方案,没有示例提及(它实际上在产品代码中工作)。
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
应该是内部的、私有的和加速的,没有堆栈跟踪:
private static class BreakLoopException extends Exception
@Override
public StackTraceElement[] getStackTrace()
return new StackTraceElement[0];
【讨论】:
实际上已经提到过,在得到-23票的答案中...***.com/a/886980/2516301。它会完成这项工作,但这是一种非常糟糕的编程习惯...... 确实如此。但是我看到了这样的遗留代码——具有几个中断条件的 4 级嵌套循环。并且使用异常而不是内联代码更具可读性。 -23 票主要是情绪评分,但是是的 - 应该谨慎使用这种方法。 如果它被分解成一个带有中心返回的单独函数调用,它会更具可读性。通常通过一些重构会变得更好,因此它作为一个独立的(通常可重用的)函数是有意义的。【参考方案23】:使用label
相当容易,您可以使用标签将外循环与内循环断开,请考虑以下示例,
public class Breaking
public static void main(String[] args)
outerscope:
for (int i=0; i < 5; i++)
for (int j=0; j < 5; j++)
if (condition)
break outerscope;
另一种方法是使用中断变量/标志来跟踪所需的中断。考虑下面的例子。
public class Breaking
public static void main(String[] args)
boolean isBreaking = false;
for (int i=0; i < 5; i++)
for (int j=0; j < 5; j++)
if (condition)
isBreaking = true;
break;
if(isBreaking)
break;
但是,我更喜欢使用第一种方法。
【讨论】:
【参考方案24】:break
、continue
和 label
的演示:
Java 关键字 break
和 continue
具有默认值。这是“最近的循环”,今天,在使用 Java 几年后,我才明白!
它似乎很少使用,但很有用。
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);
【讨论】:
【参考方案25】:for (int j = 0; j < 5; j++) //inner loop
应替换为
for (int j = 0; j < 5 && !exitloops; j++)
.
在这种情况下,如果条件为 True
,则应退出完整的嵌套循环。但是如果我们只使用exitloops
到上面的loop
for (int i = 0; i < 5 && !exitloops; i++) //upper loop
然后内循环将继续,因为没有额外的标志通知这个内循环退出。
示例:如果
i = 3
和j=2
则条件为false
。但是在内部循环的下一次迭代中j=3
然后条件(i*j)
变为9
即true
但内部循环将继续直到j
变为5
。
所以,它也必须在内部循环中使用exitloops
。
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);
【讨论】:
【参考方案26】:像@1800 INFORMATION 建议一样,使用打破内循环的条件作为外循环的条件:
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;
【讨论】:
【参考方案27】:Java 没有 C++ 中的 goto 功能。但是,goto
仍然是 Java 中的保留关键字。他们将来可能会实施它。对于您的问题,答案是 Java 中有一个称为标签的东西,您可以在其中应用 continue
和 break
语句。找到下面的代码:
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");
【讨论】:
【参考方案28】:如果是新实现,可以尝试将逻辑重写为 if-else_if-else 语句。
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
否则,您可以尝试在该特殊条件发生时设置一个标志,并在每个循环条件中检查该标志。
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,并且只是想让它工作,您可以尝试使用 labels。
【讨论】:
【参考方案29】:您只需使用标签来打破内部循环
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");
【讨论】:
【参考方案30】:您可以执行以下操作:
将局部变量设置为false
在第一个循环中设置变量true
,当你想中断时
然后你可以在外循环中检查是否设置了条件然后从外循环中中断。
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
【讨论】:
以上是关于如何打破 Java 中的嵌套循环?的主要内容,如果未能解决你的问题,请参考以下文章
如何打破 Objective-C 中的两个嵌套 for 循环?