Java Stream的groupingBy用于按分类函数分组,生成Map;可指定Map实现类型、下游聚合操作(如计数、求和)及多级分组,核心是classifier决定分组键,downstream决定组内处理方式。

Java Stream 的 groupingBy 是最常用的分组工具,核心就是传入一个分类函数(classifier),它会把流中每个元素按该函数返回的键归类,生成 Map<k list>></k>。
基础写法:按字段分组
比如有一个 Person 类,按年龄分组:
List<Person> people = Arrays.asList(
new Person("Alice", 25),
new Person("Bob", 30),
new Person("Charlie", 25)
);
Map<Integer, List<Person>> grouped = people.stream()
.collect(Collectors.groupingBy(Person::getAge));
// 结果:{25=[Alice, Charlie], 30=[Bob]}
指定 Map 实现类型(如 LinkedHashMap 保持插入顺序)
默认返回的是 HashMap,不保证顺序。想按分组顺序输出,可传入 mapFactory:
- 用
LinkedHashMap::new保持首次出现键的顺序 - 用
TreeMap::new按键自然排序
示例:
立即学习“Java免费学习笔记(深入)”;
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
Map<Integer, List<Person>> ordered = people.stream()
.collect(Collectors.groupingBy(
Person::getAge,
LinkedHashMap::new,
Collectors.toList()
));
分组后聚合:不只是 List,还能统计、求和、取平均等
第二个参数是下游收集器(downstream),控制每个分组内怎么处理数据:
-
Collectors.counting()→ 统计每组数量(返回Map<K, Long>) -
Collectors.summingInt(Person::getAge)→ 求每组年龄总和 -
Collectors.averagingDouble(Person::getSalary)→ 算平均薪资 -
Collectors.mapping(Person::getName, Collectors.joining(", "))→ 提取姓名并拼接字符串
例如按城市分组并统计人数:
Map<String, Long> cityCount = people.stream()
.collect(Collectors.groupingBy(Person::getCity, Collectors.counting()));
多级分组:嵌套 groupingBy
先按城市分,再按年龄分,形成 Map<String, Map<Integer, List<Person>>>:
Map<String, Map<Integer, List<Person>>> nested = people.stream()
.collect(Collectors.groupingBy(
Person::getCity,
Collectors.groupingBy(Person::getAge)
));
也可组合下游收集器,比如“每个城市里,按年龄统计人数”:
Map<String, Map<Integer, Long>> cityAgeCount = people.stream()
.collect(Collectors.groupingBy(
Person::getCity,
Collectors.groupingBy(Person::getAge, Collectors.counting())
));
不复杂但容易忽略细节,关键就是理清 classifier 和 downstream 的分工:前者决定“分到哪一组”,后者决定“组里怎么整理”。

















