跳出Lambda表达式forEach()循环解决思路

背景

在一次需求开发时,发现使用Lambda的forEach()跳不出循环。如下示例代码,想在遍历满足条件时跳出循环。

java 复制代码
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 4, 5, 7, 9, 11);

        list.forEach(e -> {
            if (e % 2 == 0) {
                System.out.println("foreach -- " + e);
                return;
            }
            System.out.println(e);
        });

        System.out.println(list);
    }

运行结果:

可以看出在forEach()中使用return并不会退出整个循环,和普通for循环return意义不同,仍会继续遍历。

原因

在普通for循环中,跳出循环使用break,结束本次循环使用continue,结束for循环所在的整个执行方法使用return。

java 复制代码
      for (Integer e : list) {
            if (e % 2 == 0) {
                break;  // return直接整个函数终止执行返回,break for循环方法终止执行
            }
            System.out.println(e);
        }

Lambda表达式中,函数式接口Consumer 的抽象方法accept引用实现循环体中的逻辑。

所以forEach()处理一个个的执行方法accept(t),非循环体。在执行方法中使用return将处理方法返回,但不能结束整个forEach()。

java 复制代码
    default void forEach(Consumer<? super T> action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
    }
java 复制代码
@FunctionalInterface
public interface Consumer<T> {

    void accept(T t);

    default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }
}

优化方案

跳出Lambda表达式forEach()循环解决思路有以下几种:

  • 抛异常
    在遍历时,若需要跳出循环,通过抛异常结束forEach()循环,在循环外catch异常不处理。首先此方案不够优雅,其次若循环逻辑块中有其他抛异常的地方,会受影响不易发现。
java 复制代码
   public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 4, 5, 7, 9, 11);

        try {
            list.forEach(e -> {
                if (e % 2 == 0) {
                    System.out.println("foreach -- " + e);
                    throw new RuntimeException("跳出循环");
                }
                System.out.println(e);
            });
        } catch (Exception e) {}

        System.out.println(list);
   }

执行结果:

  • 使用普通for循环

    使用普通for循环替代Lambda表达式forEach()循环,在代码块中使用break即可跳出循环。

  • 使用Lambda表达式filter()实现

    换个实现思路,诉求是遍历list遇到第一个满足条件的item跳出循环,那么转成过滤整个list,返回第一个满足条件的item。

java 复制代码
Optional<Integer> first = list.stream().filter(e -> e % 2 == 0).findFirst();
System.out.println(first.orElse(null));
  • 使用anyMatch()
    原理类似filter(),遇到满足条件的item跳出遍历返回。
java 复制代码
      list.stream().anyMatch(e -> {
            if (e % 2 == 0) {
                System.out.println("跳出循环 -- " + e);
                return true;
            }
            System.out.println(e);
            return false;
        });

执行结果:

总结

Lambda表达式forEach()函数不支持return跳出循环,不建议使用抛异常方式结束循环,可以考虑使用普通for或利用Lambda表达式的函数实现。

相关推荐
m0_571957582 小时前
Java | Leetcode Java题解之第543题二叉树的直径
java·leetcode·题解
魔道不误砍柴功4 小时前
Java 中如何巧妙应用 Function 让方法复用性更强
java·开发语言·python
NiNg_1_2344 小时前
SpringBoot整合SpringSecurity实现密码加密解密、登录认证退出功能
java·spring boot·后端
闲晨4 小时前
C++ 继承:代码传承的魔法棒,开启奇幻编程之旅
java·c语言·开发语言·c++·经验分享
Chrikk5 小时前
Go-性能调优实战案例
开发语言·后端·golang
幼儿园老大*5 小时前
Go的环境搭建以及GoLand安装教程
开发语言·经验分享·后端·golang·go
canyuemanyue5 小时前
go语言连续监控事件并回调处理
开发语言·后端·golang
杜杜的man5 小时前
【go从零单排】go语言中的指针
开发语言·后端·golang
测开小菜鸟5 小时前
使用python向钉钉群聊发送消息
java·python·钉钉
P.H. Infinity6 小时前
【RabbitMQ】04-发送者可靠性
java·rabbitmq·java-rabbitmq