Java Stream API中peek()方法使用不当引发的生产问题

早上到刚公司同事就给我发了个生产报错日志,Field 'XXX' doesn't have a default value,一看,这不就是表字段为非空字段,插入数据时该字段为空导致的么。

根据日志我定位到了写入具体的是哪张表以及组装数据的代码,示例代码:

java 复制代码
import java.util.List;

public class StudentDao {
    
    private StudentMapper studentMapper;

    public boolean saveBatch(List<StudentEntity> studentList) {
        studentList.stream().peek(studentEntity -> {
            studentEntity.setName("张三");
        });
        return studentMapper.saveBatch(studentList);
    }
}

我乍一看这代码没问题呀, 字段通过peek()方法赋值了呀,怎么还会报错呢?

文中所有peek()方法均指的是:

java 复制代码
Stream<T> peek(Consumer<? super T> action)

此时,我看到我的idea对peek()方法有个波浪线提示,我猜测有可能就是这个peek()写法有问题,于是我将光标放到peek()方法上,提示'Stream.peek()' 的结果已忽略。

当时没明白什么意思,于是我就写了个main方法,将源代码copy运行了一下,发现居然没赋值成功,字段值任然是null。

我当时一脸懵逼,我就在想难道赋值方法没执行吗?于是我就加了1行控制台输出代码并且加了个断点,重新执行后发现控制台没有输出,也没进断点。

这个peek()方法平时用的不多,也没注意去看,只知道它主要是支持调试,很少用它来对集合元素进行赋值,一般对集合元素遍历赋值都用 forEach()方法,于是百度搜了一下,发现了这个方法的真谛

peek()方法是 Strean 接口中的一个中间操作,它允许你在流的每个元素上执行一个操作,但是这个操作是在最终的终端操作执行前进行的。

然而,如果 peek()是流中唯一的操作,那么它实际上不会执行。

这是因为peek ()本身并不是一个 终端操作,它不会触发流的执行。

在Java 8及以后的版本中,流的执行是情性的,这意味着流操作不会立即执行,而是在遇到终端操作时才会实际执行。

什么是终端操作,在Stream API 中终端操作有很多方法,以下举几个例子,在Stream API中搜terminal operation 就会很清楚的发现哪些方法是终端操作了

java 复制代码
<R, A> R collect(Collector<? super T, A, R> collector);
Optional<T> min(Comparator<? super T> comparator);
Optional<T> max(Comparator<? super T> comparator);
long count();
void forEach(Consumer<? super T> action);

总结一下,就是peek()方法中的代码要执行,必须后面要跟上终端操作方法,不然代码不会执行。

问题定位了,于是乎,我连忙打开代码提交记录,先看下是谁写的代码,把问题的锅先甩出去再说(PS:此处奸笑一下),最后发现这个代码1个将近10年开发经验的老鸟写的,不过这哥们已经离职了。不过这个BUG,也算是给我这个老鸟上了一课。

相关推荐
带刺的坐椅1 小时前
用 ChatModel 构建 LLM 驱动的 Java 应用
java·ai·llm·solon·rag·chatmodel
用户3721574261353 小时前
Java 将 Word 文档转换为 Markdown:基础转换与导出选项详解
java
行者全栈架构师3 小时前
PolarDB + Spring Boot 实战:从自建MySQL到云原生数据库的零停机迁移
java·后端·架构
karry_k19 小时前
MyBatis批量insert-select踩坑:useGeneratedKeys=true 可能让PostgreSQL返回大量插入结果
java·后端
karry_k19 小时前
PostgreSQL 在 MyBatis 中执行正常 SQL 失效:一次 DELETE USING 踩坑记录
java·后端
SamDeepThinking1 天前
从源码到代码:MyBatis-Flex 与 MyBatis-Plus 的逐项对比
java·后端·程序员
她的男孩1 天前
Spring Boot 接 Flowable 工作流:用 3 个注解搭一个请假审批流程
java·后端·架构
荣码1 天前
LLM结构化输出:让AI返回JSON而不是废话,我踩了4个坑
java·python
plainGeekDev1 天前
Gson → kotlinx.serialization
android·java·kotlin