召唤小埋
    0%

    Java 如何跳出forEach

    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循环遍历。

    • 创建时间: 2019-11-04 11:26:27
    • 修改时间: 2020-02-13 16:43:29
    • 本文作者: Morty.ROY
    • 本文链接: https://www.royians.cn/2019/11.04.4364ab65/
    • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!