Java如何按startDate和source双字段过滤List,保留endDate更大的对象
解决方案
你只需要将toMap的key从单一的startDate改为同时包含startDate和source的组合键即可,以下是具体实现:
方案1:直接扩展原有代码
最简便的方式是用AbstractMap.SimpleEntry作为组合键,无需额外定义类:
import java.util.AbstractMap; import java.util.Collection; import java.util.function.Function; import java.util.stream.Collectors; Collection<A> result = list1.stream() .collect(Collectors.toMap( // 组合startDate和source作为分组key a -> new AbstractMap.SimpleEntry<>(a.getStartDate(), a.getSource()), Function.identity(), // 保留endDate更大的对象,原有逻辑不变 (a, b) -> a.getEndDate().after(b.getEndDate()) ? a : b )) .values();
如果是Java 16及以上版本,也可以用record定义组合键,可读性更好:
// 定义不可变的组合键类 record StartSourceKey(Timestamp startDate, String source) {} Collection<A> result = list1.stream() .collect(Collectors.toMap( a -> new StartSourceKey(a.getStartDate(), a.getSource()), Function.identity(), (a, b) -> a.getEndDate().after(b.getEndDate()) ? a : b )) .values();
方案2:分组后取最大值实现
如果你更喜欢语义更清晰的写法,可以先按组合键分组,再从每组中取endDate最大的对象:
import java.util.AbstractMap; import java.util.Collection; import java.util.Comparator; import java.util.Optional; import java.util.stream.Collectors; Collection<A> result = list1.stream() .collect(Collectors.groupingBy( a -> new AbstractMap.SimpleEntry<>(a.getStartDate(), a.getSource()), Collectors.maxBy(Comparator.comparing(A::getEndDate)) )) .values() .stream() .filter(Optional::isPresent) .map(Optional::get) .collect(Collectors.toList());
注意事项
- 不要用字符串拼接的方式生成组合键(比如
startDate.toString() + "_" + source),如果字段值包含拼接用的分隔符会出现key冲突问题 - 如果
endDate可能为null,需要在比较逻辑中增加空值判断,避免空指针异常 Timestamp和String都已经正确实现了equals和hashCode方法,作为组合键的组成部分不会有问题
内容的提问来源于stack exchange,提问作者Ishan Arora
相关产品推荐
相关产品推荐

