如何修改Java Stream代码对所有元素执行ifPresentOrElse()操作
问题根因
原代码无法遍历所有元素的核心原因是调用了findFirst()短路终端操作:
- 该方法会在流中匹配到第一个元素后立刻终止整个流的遍历,剩余8个元素根本不会进入处理流程
- 方法返回值是仅存储单个元素的
Optional实例,后续调用的ifPresentOrElse只会对这单个元素生效,自然无法覆盖全量列表元素
正确修改方案
要实现对所有元素生效,需要移除findFirst()调用,同时要对齐原代码的异常逻辑:只要存在任意一个列找不到对应加密器,就抛出异常,不执行任何加密操作。推荐采用先全量校验、再批量执行的写法,避免出现部分加密、部分未执行的不一致问题:
import java.util.Objects; import java.util.List; // 1. 先取出所有列对应的加密器 List<ColumnEncryptor> allEncryptors = columns.stream() .map(columnEncryptors::get) .toList(); // 2. 全量校验,只要有一个加密器不存在就抛异常 if (allEncryptors.stream().anyMatch(Objects::isNull)) { throw new IllegalArgumentException("No encryptor"); } // 3. 校验通过后,对所有加密器执行加密逻辑 allEncryptors.forEach(encryptor -> encryptor.encrypt(bankTransaction));
写法差异说明
如果不需要保证“全量校验通过才执行”的原子性,也可以用更紧凑的单流写法,但是要注意该写法会按顺序执行加密,遍历到缺失加密器的位置才抛异常,此时之前遍历到的元素已经完成加密,会产生部分执行的结果:
columns.stream() .map(columnEncryptors::get) .forEach(encryptor -> { if (encryptor == null) { throw new IllegalArgumentException("No encryptor"); } encryptor.encrypt(bankTransaction); });
注意:不要使用
peek()方法承载业务逻辑,该方法是JDK专门为流调试设计的,在流的部分优化场景下可能不会被触发执行,会导致业务逻辑丢失。
内容的提问来源于stack exchange,提问作者Dennis van Putten
相关产品推荐
相关产品推荐

