Java Stream API通过Collectors.groupingBy()实现分组统计,支持单字段分组、数量统计、求和、平均值、最大值等聚合操作,以及多级分组和嵌套统计,并需注意空值处理、有序性保障及并行流优化。

Java Stream API 提供了简洁、函数式的数据处理方式,分组统计是其中高频使用场景。核心在于 Collectors.groupingBy() 及其组合用法,配合下游收集器(如 counting、summingInt、averagingDouble、toSet 等)可灵活完成各类分组聚合需求。
基础分组:按单字段分类
最常见的是按某个属性对对象列表分组,生成 Map<K, List<T>>:
List<Person> people = Arrays.asList(
new Person("Alice", "Engineering", 8500),
new Person("Bob", "Marketing", 6200),
new Person("Charlie", "Engineering", 9100)
);
// 按部门分组
Map<String, List<Person>> byDept = people.stream()
.collect(Collectors.groupingBy(Person::getDepartment));
// 结果:{"Engineering": [Alice, Charlie], "Marketing": [Bob]}
分组 + 聚合:统计数量、求和、平均值
通过 groupingBy 的下游收集器,避免手动遍历计算:
-
统计每组人数:用
Collectors.counting() -
计算每组薪资总和:用
Collectors.summingInt(Person::getSalary) -
计算每组平均薪资:用
Collectors.averagingDouble(Person::getSalary) -
获取每组最高薪资:用
Collectors.maxBy(Comparator.comparingInt(Person::getSalary))
Map<String, Long> countByDept = people.stream()
.collect(Collectors.groupingBy(Person::getDepartment, Collectors.counting()));
Map<String, Integer> sumByDept = people.stream()
.collect(Collectors.groupingBy(Person::getDepartment, Collectors.summingInt(Person::getSalary)));
多级分组与嵌套统计
支持嵌套 groupingBy 实现“部门 → 职级”二级分组,或结合其他收集器做深层聚合:
立即学习“Java免费学习笔记(深入)”;
- 两级分组:
groupingBy(dept, groupingBy(level)) - 分组后取每组前 N 名:
groupingBy(dept, collectingAndThen(toList(), list -> list.stream().sorted(...).limit(3).toList())) - 分组并同时统计多个指标(需自定义对象或使用 Map.Entry)
注意事项与优化建议
实际使用中需注意几点:
- groupingBy 默认使用
HashMap,若需有序结果,可用LinkedHashMap::new作为第三个参数 - 空值可能导致 NullPointerException,建议提前过滤或使用
Objects.toString(key, "unknown")安全转换 - 大数据量下,parallelStream() 可提升性能,但需确保下游收集器线程安全(Collectors 提供的多数是安全的)
- 避免在 lambda 中做重操作(如 DB 查询、IO),保持流操作纯函数特性



















