
本文介绍如何使用 java 8 的 stream api,对包含 name 和 version 字段的对象列表进行分组,并高效提取每个 name 对应的最高版本对象,避免手动循环与冗余比较。
在 Java 8 中,借助 Stream、Collectors.groupingBy 和 Collectors.collectingAndThen 等特性,我们可以以声明式、函数式的方式优雅地解决“按字段分组 + 取每组极值”的典型需求。以下以一个完整可运行的示例展开说明。
? 示例实体类
首先定义待处理的对象(假设为 AppVersion):
public static class AppVersion {
private final String name;
private final int version;
public AppVersion(String name, int version) {
this.name = name;
this.version = version;
}
// getter 方法(必须提供,用于 Stream 操作)
public String getName() { return name; }
public int getVersion() { return version; }
@Override
public String toString() {
return String.format("{\"name\": \"%s\", \"version\": %d}", name, version);
}
}✅ 核心解决方案:Stream + groupingBy + maxBy
利用 Collectors.groupingBy 按 name 分组,再嵌套 Collectors.collectingAndThen 配合 Collectors.maxBy 获取每组中 version 最大的对象:
Listversions = Arrays.asList( new AppVersion("ss", 1), new AppVersion("ss", 2), new AppVersion("sam", 1), new AppVersion("sam", 2), new AppVersion("sim", 1) ); List latestPerName = versions.stream() .collect(Collectors.groupingBy( AppVersion::getName, Collectors.collectingAndThen( Collectors.maxBy(Comparator.comparingInt(AppVersion::getVersion)), Optional::get ) )) .values() .stream() .toList(); // Java 16+;若用低版本,替换为 .collect(Collectors.toList()) System.out.println(latestPerName); // 输出:[{"name": "ss", "version": 2}, {"name": "sam", "version": 2}, {"name": "sim", "version": 1}]
✅ 优势说明:
立即学习“Java免费学习笔记(深入)”;
- 一行逻辑表达分组与聚合,语义清晰;
- 自动处理空组(Optional::get 在本例中安全,因每组至少有一个元素;如需更健壮,可用 orElse(null) 并过滤 null);
- 无副作用,符合函数式编程原则。
⚠️ 注意事项与最佳实践
-
Optional::get 风险提示:maxBy 返回 Optional
,若某组为空(实际不会发生,因分组源非空),直接调用 get() 会抛 NoSuchElementException。生产环境建议改用: Collectors.collectingAndThen( Collectors.maxBy(Comparator.comparingInt(AppVersion::getVersion)), opt -> opt.orElse(null) )并在后续 .filter(Objects::nonNull) 过滤掉可能的 null。
性能考量:该方案时间复杂度为 O(n),仅遍历一次流;相比双层循环或多次 stream().max() 调用,效率更优。
扩展性提示:若需同时获取多个极值(如 top-3 版本),可改用 Collectors.collectingAndThen(Collectors.toList(), list -> list.stream().sorted(...).limit(3).toList())。
? 总结
Java 8 Stream 提供了强大而简洁的分组聚合能力。针对“按某属性分组并取每组最大版本对象”这一常见场景,推荐采用 groupingBy + maxBy 组合方案——代码简短、可读性强、线程安全(输入不可变时),且天然支持并行流(.parallelStream())以应对大数据量场景。掌握此模式,可快速迁移解决类似“最新订单”“最高评分商品”等业务问题。










