StackOverflow上看到一个以前没有意识到的问题,怎样能跳出forEach循环呢?

问题

我的第一想法是,break不可以使用吗?continue呢?

探索

于是我在IDEA中试了一下:

1
2
3
4
5
6
7
8
9
10
11
12
@Test
void testBreak() {
LinkedList<Integer> integers = new LinkedList<Integer>(Collections.singleton(10));
Random random = new Random();
for (int i = 0; i < 10; i++) {
integers.add(random.nextInt(20));
}
integers.forEach((number) -> {
System.out.println("Number: " + number);
break;
});
}

结果编译时报错:

E

接着我试了continue,同样报错。

那怎么办了?

我接着试了return

1
2
3
4
5
6
7
8
9
10
@Test
void testBreak() {
List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5);
integers.forEach((number) -> {
System.out.println("Number: " + number);
if (number == 2) {
return;
}
});
}

运行结果:

E

没卵用

然后我发现粗心的把输出语句写在return上面了

1
2
3
4
5
6
7
8
9
10
@Test
void testBreak() {
List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5);
integers.forEach(number -> {
if (number == 2) {
return;
}
System.out.println("Number: " + number);
});
}

结果如下:

E

相当于continue

continue替代者找到了,那如何实现break呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class BreakException extends RuntimeException{ }
...
@Test
void testBreak() {
List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5);
try {
integers.forEach(number -> {
if (number == 2) {
throw new BreakException();
}
System.out.println("Number: " + number);
});
} catch (BreakException e) {
System.out.println("Break");
}
}

结果:
image.png

总结

forEach()方法不支持break、continue,是因为源码中:

1
2
3
4
5
6
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}

for循环是在方法体内的,如果在forEach的lambda表达式中使用break和continue,是没有效果的。我们找到的替代方法是使用return;达到continue的效果,使用throw异常的方式取得和break一样的效果。

但是感觉有点麻烦了,不如还是直接使用增强for循环遍历。