Java 8 Stream结合Filter、Map与Count实现唯一值校验问题
合并Java Stream筛选、提取与唯一值校验的优化方案
嘿,我来帮你搞定这个问题!你的需求其实可以通过Stream的链式操作一步完成,既不用拆分两步,还能彻底避免空指针异常,代码也更简洁。
核心思路回顾
你需要三个核心操作:
- 过滤出CAR_ID字段已初始化的
CarDetails对象 - 提取这些对象的
carId字段(允许null,因为null也算一个独立的值) - 校验去重后的
carId数量是否为1:是则返回该值,否则返回null
优化后的完整代码
import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; // 处理原列表可能为null的情况,同时完成所有逻辑 Integer carId = Optional.ofNullable(carDetails) // 如果原列表是null,替换为空列表,避免stream操作时的NPE .orElse(Collections.emptyList()) .stream() // 第一步:过滤出CAR_ID字段已初始化的对象,避免提取未初始化字段的NPE .filter(car -> car.isInitialized(CarDetail.Fields.CAR_ID.getCode())) // 第二步:提取carId,允许返回null(null会被当作独立值参与去重) .map(CarDetails::getCarId) // 第三步:去重,包括重复的null值 .distinct() // 收集到临时列表后,直接判断大小并返回结果 .collect(Collectors.collectingAndThen(Collectors.toList(), filteredDistinctList -> { // 只有去重后恰好1个元素时返回它,否则返回null return filteredDistinctList.size() == 1 ? filteredDistinctList.get(0) : null; }));
代码逐行解释
- 处理原列表为null的情况:用
Optional.ofNullable+orElse把null列表转换成空列表,避免调用stream()时抛出空指针异常。 - 过滤已初始化对象:
filter确保我们只处理CAR_ID字段已初始化的对象,防止调用getCarId时因字段未初始化触发NPE(假设isInitialized是可靠的校验方法)。 - 提取carId:
map直接提取字段,即使返回null也保留——因为你的示例里{3,null}要返回null,说明null属于一个不同的“值”。 - 去重操作:
distinct()会自动处理重复的carId,包括重复的null(比如两个null会被合并成一个)。 - 最终判断:用
collectingAndThen把“收集列表”和“判断大小”合并成一步:如果去重后的列表大小为1,就返回唯一的元素;否则返回null,完全符合你的需求。
验证你的示例场景
- 场景1:
CarId为{3,4,null}→ 去重后列表大小为3 → 返回null - 场景2:
CarId为{3,null}→ 去重后列表大小为2 → 返回null - 场景3:
CarId为{3,3,3}→ 去重后列表大小为1 → 返回3
所有场景都完美符合预期,而且全程没有空指针风险!
内容的提问来源于stack exchange,提问作者shreya
相关产品推荐
相关产品推荐

