collectors.groupingby通过嵌套下游收集器实现多级分组,形成map套map结构;支持两级、三级甚至更多层级,最内层可结合counting、summingint、mapping等增强实用性。

Java 中 Collectors.groupingBy 本身只支持单级分组,但通过嵌套调用可以自然实现多级分组——本质是“分组结果的值再次被分组”,形成 Map 套 Map 的结构。
两级分组:外层按部门,内层按职位
假设有一个员工列表,想先按 department 分组,再在每个部门内按 position 分组:
Map<string map list>>> deptToPositionToEmployees =
employees.stream()
.collect(Collectors.groupingBy(
Employee::getDepartment,
Collectors.groupingBy(Employee::getPosition)
));</string>
说明:
- 第一个参数 Employee::getDepartment 是外层分组键;
- 第二个参数是下游收集器(即对每个部门内的员工再执行一次 groupingBy);
- 结果类型为 Map<string map list>>></string>。
三级分组:嵌套三层 groupingBy
若还需按年龄区间(如 "20-30"、"31-40")进一步细分,可继续嵌套:
Map<string map list>>>> result =
employees.stream()
.collect(Collectors.groupingBy(
Employee::getDepartment,
Collectors.groupingBy(
Employee::getPosition,
Collectors.groupingBy(e -> {
int age = e.getAge();
if (age <p>注意:<br>
- 每一层 <code>groupingBy</code> 都作为上一层的下游收集器;<br>
- 类型会逐层加深,读写时需注意空指针(建议配合 <code>Optional</code> 或判空处理);<br>
- 键函数支持任意表达式或方法引用,不局限于字段。</p>
<h3>结合 downstream 收集器增强实用性</h3>
<p>多级分组中,最内层不一定非要是 <code>List</code>。例如统计每部门每职位的人数:</p>
<ul><li>用 <code>Collectors.counting()</code> 替换最内层的 <code>groupingBy</code>:</li></ul>
<pre class="brush:java;toolbar:false;">Map<string map long>> deptToPositionToCount =
employees.stream()
.collect(Collectors.groupingBy(
Employee::getDepartment,
Collectors.groupingBy(
Employee::getPosition,
Collectors.counting()
)
));</string>
- 也可用
Collectors.summingInt求薪资总和、Collectors.mapping提取姓名列表等。
使用 groupingBy + mapping 简化嵌套逻辑
如果只是想“分组后提取某个属性”,避免深层 Map,可用 mapping 配合 toList 或 toSet:
Map<string map set>>> deptToPositionToNames =
employees.stream()
.collect(Collectors.groupingBy(
Employee::getDepartment,
Collectors.groupingBy(
Employee::getPosition,
Collectors.mapping(Employee::getName, Collectors.toSet())
)
));</string>
这样内层不再是 List<employee></employee>,而是更轻量的 Set<string></string>,适合只关心名称、去重等场景。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











