java stream 的 groupingby 是实现分组统计最常用、最直观的方式,它能像 sql 的 group by 一样对数据按某个字段聚合,并支持嵌套统计(如计数、求和、平均值等),无需手动遍历 map 构建。

Java Stream 的 groupingBy 是实现分组统计最常用、最直观的方式,它能像 SQL 的 GROUP BY 一样对数据按某个字段聚合,并支持嵌套统计(如计数、求和、平均值等),无需手动遍历 Map 构建。
基础分组:按单个字段分类
最简单的用法是将流中元素按某个属性分组,返回 Map<k list>></k>:
List<person> people = Arrays.asList(
new Person("Alice", "IT", 8000),
new Person("Bob", "HR", 6500),
new Person("Charlie", "IT", 9200)
);
// 按部门分组
Map<string list>> byDept = people.stream()
.collect(Collectors.groupingBy(Person::getDepartment));
// 结果:{"IT": [Alice, Charlie], "HR": [Bob]}
</string></person>
带下游收集器的聚合统计
真正体现“类似数据库统计”的能力,在于配合下游收集器(downstream collector)做进一步计算:
-
统计每组数量:
Collectors.counting() -
求每组薪资总和:
Collectors.summingDouble(Person::getSalary) -
算每组平均薪资:
Collectors.averagingDouble(Person::getSalary) -
取每组最高/最低薪资:
Collectors.maxBy(Comparator.comparingDouble(Person::getSalary))
例如统计各部门人数和平均薪资:
Map<string double> avgSalaryByDept = people.stream()
.collect(Collectors.groupingBy(
Person::getDepartment,
Collectors.averagingDouble(Person::getSalary)
));
// {"IT": 8600.0, "HR": 6500.0}
</string>
多级分组与复合键
支持嵌套分组,模拟 GROUP BY dept, role:
// 先按部门,再按角色分组
Map<string map list>>> nested = people.stream()
.collect(Collectors.groupingBy(
Person::getDepartment,
Collectors.groupingBy(Person::getRole)
));
</string>
若需自定义复合键(如部门+角色拼接),可用 groupingBy(p -> p.getDepartment() + "-" + p.getRole()),更灵活且避免嵌套 Map 的复杂性。
空组处理与自定义 Map 类型
默认返回 HashMap,但可指定类型(如 TreeMap 实现自然排序):
Map<string long> countSorted = people.stream()
.collect(Collectors.groupingBy(
Person::getDepartment,
TreeMap::new, // 指定 map 类型
Collectors.counting()
));
</string>
若某些分组可能为空(如某部门无人),可结合 Collectors.collectingAndThen 或预置 key 初始化,但通常业务中更倾向用 Optional 或判空处理,而非强制补零。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











