跳转到主内容
极星编程网:以代码为星,赴技术山海!

如何使用 Java Stream 将对象按字段分组并聚合数值

本文详解如何利用 Java 8 Stream API 的 Collectors.groupingBy 与 Collectors.summingInt,将对象集合(如 School)按某个分类字段(如 country)分组,并对关联数值字段(如 numStudents)求和,生成键值映射(Map)。 本文详解如何利用 java 8 stream api 的 `collectors.groupingby` 与 `collectors.summingint`,将对象集合(如 school)按某个分类字段(如 country)分组,并对关联数值字段(如 numstudents)求和,生成键值映射(map )。 在实际开发中,常需将对象流按某一属性归类,并对另一数值属性执行聚合操作(如求和、平均、计数等)。以 School 类为例——它包含 String country 和 int numStudents 两个关键字段,我们希望将所有学校按国家分组,并汇总各国学生总数。 最简洁、函数式且线程安全的实现方式是使用 Stream.collect() 配合复合收集器:
Map countryToNumStudents = allSchools .collect(Collectors.groupingBy( School::getCountry, // 分组键:国家名 Collectors.summingInt(School::getNumStudents) // 聚合操作:对学生数求和 ));
这段代码逻辑清晰:groupingBy 指定分组依据(getCountry()),而第二个参数 summingInt 则定义了每个分组内对 getNumStudents() 的整型值进行累加。最终返回一个 Map,例如:{"USA" → 20000, "Taiwan" → 10000, "Japan" → 8500}。 ⚠️ 注意事项: 立即学习 “ Java免费学习笔记(深入) ”; Eclipse导入Android或其他的JAVA项目的正确方法 WORD版 本文档主要讲述的是Eclipse导入Android或其他的JAVA项目的正确方法;希望本文档会给有需要的朋友带来帮助;感兴趣的朋友可以过来看看 下载 School::getCountry 返回的键值必须具备合理 equals() 和 hashCode() 实现(字符串默认满足); 若某 School 对象的 getCountry() 返回 null,默认会抛出 NullPointerException;如需支持 null 键,可改用 Collectors.groupingBy(s -> s.getCountry() == null ? "UNKNOWN" : s.getCountry(), ...) 进行预处理; summingInt 仅适用于 int 类型;若 getNumStudents() 返回 long 或 double,请分别使用 summingLong 或 summingDouble; 该操作是终端操作,不可重复调用流;若需多次使用原始数据,建议先收集为 List 再创建新流。 作为对比,传统循环写法虽可读性强,但冗长且易出错:
Map countryToNumStudents = new HashMap<>(); for (School school : allSchools.toList()) { // 假设 allSchools 已转为 List String country = school.getCountry(); int students = school.getNumStudents(); countryToNumStudents.merge(country, students, Integer::sum); }
推荐使用 merge 替代手动 containsKey + get + put,更简洁安全。 总结:Java Stream 的 groupingBy 与下游收集器组合,是处理“分类-聚合”场景的标准范式。掌握 Collectors.summingInt、averagingDouble、counting 等常用下游收集器,能显著提升数据转换代码的表达力与健壮性。

相关文章