Java Stream如何分组单次遍历获取每组stageNumber最大对象
Java Stream 按字段分组取组内最大值实现方案
问题根因说明
你之前的实现报错原因很明确:
groupingBy(Function.identity(), TreeMap::new, toList())的分组键是MyObject实例本身,而非你需要分组的stageToCalc字段;同时TreeMap要求键实现Comparable排序接口,你的实体类未实现该接口,因此抛出ClassCastException。- 直接调用流的
max()方法无法通过编译,是因为max()是针对整个流的全局终端操作,无法实现按分组分别计算最大值的逻辑。
另外你贴的初始过滤代码存在语法错误:x.getFlag == 1中getFlag是方法调用,需要补括号写成x.getFlag() == 1,否则无法通过编译。
单次遍历最优实现
使用Collectors.toMap即可实现单次O(n)遍历完成需求,不需要全量分组后二次遍历,也不需要写多层for循环,适配动态分组场景:
import java.util.function.Function; import java.util.stream.Collectors; // 接原有业务逻辑 List<MyObject> result = objects.stream() .filter(x -> x.getFlag() == 1) .filter(x -> x.getAmount() != null) .collect(Collectors.toMap( // 按stageToCalc字段作为分组key MyObject::getStageToCalc, // 映射value为对象本身 Function.identity(), // 同key(同分组)冲突时,保留stageNumber更大的对象 (oldObj, newObj) -> oldObj.getStageNumber() > newObj.getStageNumber() ? oldObj : newObj )) // 提取所有分组筛选后的结果 .values() // 转成List返回,Java 16+可直接用.toList(),低版本用Collectors.toList() .stream().collect(Collectors.toList());
运行逻辑验证
针对你给出的4个测试对象,执行逻辑如下:
- 遍历到对象1(stageToCalc=1,stageNumber=2):Map中无对应key,直接存入
- 遍历到对象2(stageToCalc=1,stageNumber=5):key已存在,比较后stageNumber更大,替换原有对象1
- 遍历到对象3(stageToCalc=7,stageNumber=9):Map中无对应key,直接存入
- 遍历到对象4(stageToCalc=7,stageNumber=10):key已存在,比较后stageNumber更大,替换原有对象3
- 最终返回结果正好是你需要的对象2、对象4。
该实现不会像
groupingBy那样先把所有同组对象暂存到List再二次遍历找最大值,遍历过程中直接完成组内比较淘汰,内存占用和执行效率都是最优的。
内容的提问来源于stack exchange,提问作者Daniel R
相关产品推荐
相关产品推荐

