Java Stream中基于双条件过滤数据的实现方法
问题:按carNum去重并优先保留carEngine非空的记录
定义的Car类
public class Car { Long carNum; String carEngine; // 假设存在对应的getter方法:getCarNum()、getCarEngine() }
原始数据列表
原始List中的Car数据如下:
Car(carNum=1, carEngine=S02K), Car(carNum=1, carEngine=null), Car(carNum=2, carEngine=null), Car(carNum=2, carEngine=S9K), Car(carNum=3, carEngine=null)
需求说明
需要过滤出满足以下条件的Car列表:
- 每个carNum唯一,无重复
- 同一carNum存在多条记录时,选取carEngine不为null的记录
- 某carNum仅存在一条记录且carEngine为null时,保留该记录
现有实现的问题
当前使用distinctByKey方法按carNum去重:
public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) { Set<Object> seen = ConcurrentHashMap.newKeySet(); return t -> seen.add(keyExtractor.apply(t)); }
调用方式:
carList.stream().filter(distinctByKey(Car::getCarNum)).collect(Collectors.toList());
该实现的问题是:去重逻辑仅根据carNum第一次出现的顺序保留记录,如果同一carNum的记录中,carEngine为null的先出现,就会被保留,而跳过后面非null的记录,无法满足需求。
解决方案
方案一:分组后筛选每组最优记录
通过groupingBy按carNum分组,再对每个分组筛选符合要求的记录,逻辑清晰且不依赖原始数据顺序:
List<Car> result = carList.stream() // 按carNum分组,key为carNum,value为对应Car的列表 .collect(Collectors.groupingBy(Car::getCarNum)) .values() // 取出所有分组的Car列表 .stream() // 处理每个分组:优先选carEngine非null的,没有则保留第一条 .map(group -> group.stream() .filter(car -> car.getCarEngine() != null) .findFirst() .orElse(group.get(0))) .collect(Collectors.toList());
方案二:先排序再去重
先对列表排序,让同一carNum下carEngine非null的记录排在前面,再用原有的distinctByKey去重:
List<Car> result = carList.stream() // 排序规则:carEngine非null的排在同carNum记录的前面 .sorted((c1, c2) -> { if (c1.getCarEngine() != null && c2.getCarEngine() == null) { return -1; } else if (c1.getCarEngine() == null && c2.getCarEngine() != null) { return 1; } return 0; }) .filter(distinctByKey(Car::getCarNum)) .collect(Collectors.toList());
两种方案最终都会得到预期输出:
Car(carNum=1, carEngine=S02K), Car(carNum=2, carEngine=S9K), Car(carNum=3, carEngine=null)
内容的提问来源于stack exchange,提问作者Vamsi
相关产品推荐
相关产品推荐

