天天看点

Java8 lambda 表达式 forEach 如何提前终止?

作者:Java技术汇

在 Java8 中,Lambda 表达式极大地简化了代码的编写,并且提高了代码的可读性和可维护性。而 forEach 方法也是 Lambda 表达式中经常用到的一个方法,它能够迭代集合中的元素,对每个元素执行指定的操作。然而,在某些情况下,我们可能需要在迭代过程中提前终止,这时该怎么做呢?

在 Java8 以前,可以使用 break 关键字或者 return 语句来跳出循环,但在 Java8 中,由于 forEach 方法是基于 Lambda 表达式实现的,无法直接使用上述方式跳出循环。但是,我们还有其他方式来实现迭代过程中的提前终止。

Java8 lambda 表达式 forEach 如何提前终止?

一、使用匿名内部类

如果你想要提前终止迭代,可以使用 Java 传统的方式,使用带有返回值的匿名内部类,并在使用 forEach 方法时调用它。

复制代码List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);
AtomicBoolean isTerminate = new AtomicBoolean(false);

list.forEach(new Consumer<Integer>() {
    @Override
    public void accept(Integer integer) {
        if(integer == 3){
            isTerminate.set(true);  // 终止迭代
        }
        System.out.println(integer);
    }
    public boolean isTerminated(){
        return isTerminate.get();   // 返回是否终止迭代
    }
});

if(isTerminate.get()){
    System.out.println("Terminated before all elements are processed!");
}
           

在上述代码中,我们通过 AtomicBoolean 维护了一个状态变量 isTerminate,初始值为 false。然后在匿名内部类中的 accept 方法中进行条件判断,如果满足退出条件,则将 isTerminate 置为 true,接着在匿名内部类中新增了一个方法 isTerminated(),用于返回状态变量 isTerminate 的当前值。最后,在使用 forEach 方法时调用匿名内部类,并根据返回值判断是否提前终止循环。

二、使用 Stream API

除了使用传统的匿名内部类之外,还可以使用 Stream API 来实现提前终止循环的功能。

复制代码AtomicBoolean isTerminate = new AtomicBoolean(false);
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);

list.stream().peek(i -> {
        if (i == 3) {
            isTerminate.set(true);
        }
    }).forEach(System.out::println);

if (isTerminate.get()) {
    System.out.println("Terminated before all elements are processed!");
}
           

在上述代码中,我们首先创建一个存储状态的 AtomicBoolean 对象,在 Stream 中通过 peek 操作进行条件判断并改变其状态,最后使用 forEach 方法对结果进行输出,当条件成立时,isTerminate 被修改为 true,catch一掉即可 break 执行。最后使用 isTerminate 来判断是否提前终止了循环。

三、使用 Optional API

依然可以使用 Stream API,不过在这种方式中我们利用 Optional API 的 ifPresent 方法来进行提前终止操作, 当条件成立时直接执行该方法即可。

复制代码List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);

Optional<Integer> opt = list.stream().filter(i-> i == 3).findFirst();

opt.ifPresent(integer -> {
    System.out.println("Terminated before all elements are processed!");
});
list.forEach(System.out::println);
           

在上述代码中,filter 方法用于根据指定的条件筛选集合中的元素,findFirst() 方法用于找到符合条件的第一个元素。如果找到则可以调用 ifPresent 方法,在里面打印需要打印的结果即可。

四、异常抛出方式提前终止

还有一种方法也是比较实用的,就是在 Lambda 表达式中通过抛出异常的方式提前退出迭代。虽然这种方法可能与 Java 异常处理机制的初衷不符,但当确实存在需要提前终止迭代的情况时,可以考虑使用该方式。

复制代码public class BreakException extends RuntimeException {

}

public static void main(String[] args) {
    List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);

    try {
        list.forEach(i -> {
            if (i == 3) throw new BreakException();
            System.out.println(i);
        });
    } catch (BreakException e) {
        //不做操作
    }
}
           

在上述代码中,我们定义了一个自定义异常 BreakException,并在 Lambda 表达式中检查退出条件,当条件成立时抛出该异常。这样可以直接通过捕获该异常来提前终止循环。

总结:

以上四种方法都能够实现在迭代过程中提前终止,具体选择哪种方法取决于具体业务需求和个人喜好。需要注意的是,在使用异常方式时应确保该方式不会对系统的性能造成影响。总的来说,Lambda 表达式及其相关的 API 为我们提供了更加简单、灵活、高效的编程工具,需要我们按照自己的场景进行使用,同时也应当注意其优缺点及适用场景。

继续阅读