
本文详解如何使用 Java 8 Streams 的 groupingBy 与 flatMapping 对 Map 按大写键聚合,将原 Map 中多个同名(忽略大小写)键对应的 List 合并为单个扁平化列表,避免嵌套 List。
本文详解如何使用 java 8 streams 的 `groupingby` 与 `flatmapping` 对 map 按大写键聚合,将原 map 中多个同名(忽略大小写)键对应的 `list>`。
在实际开发中,我们常需对不规范的键(如大小写混用的部门名 "depa"、"depA"、"DEPA")进行标准化归一(如全部转为大写),再将对应值(List<employee></employee>)合并为统一分组。若直接使用 Collectors.mapping,会导致下游收集结果为 List<list>></list>——即每个分组内是一个“员工列表的列表”,而非期望的“所有员工的扁平列表”。
正确解法是使用 Collectors.flatMapping:它接受一个 Function super T, ? extends Stream extends U>>,将每个原始值映射为一个流,再将所有流扁平合并(flatten) 后统一收集,从而自然得到 List<employee></employee>。
以下是完整可运行示例:
import java.util.*;
import java.util.stream.Collectors;
class Employee {
int id;
String name;
Employee(int id, String name) {
this.id = id;
this.name = name;
}
// getter/setter 略(按需补充)
public int getId() { return id; }
public String getName() { return name; }
@Override
public String toString() {
return "Employee{id=" + id + ", name='" + name + "'}";
}
}
public class GroupByKeyUppercase {
public static void main(String[] args) {
Map<String, List<Employee>> firstMap = new HashMap<>();
firstMap.put("depa", Arrays.asList(new Employee(1, "aa")));
firstMap.put("depA", Arrays.asList(new Employee(2, "bb")));
firstMap.put("depC", Arrays.asList(new Employee(3, "cc")));
firstMap.put("depd", Arrays.asList(new Employee(4, "dd")));
firstMap.put("depak", Arrays.asList(new Employee(5, "A1"), new Employee(6, "A2")));
firstMap.put("depaK", Arrays.asList(new Employee(7, "A3")));
firstMap.put("depAk", Arrays.asList(new Employee(8, "A4")));
firstMap.put("depAK", Arrays.asList(new Employee(9, "A5")));
// ✅ 正确:使用 flatMapping 实现扁平合并
Map<String, List<Employee>> secondMap = firstMap.entrySet().stream()
.collect(Collectors.groupingBy(
entry -> entry.getKey().toUpperCase(), // 键转大写归一
Collectors.flatMapping(
entry -> entry.getValue().stream(), // 将每个 List<Employee> 转为 Stream<Employee>
Collectors.toList() // 合并为单个 List<Employee>
)
));
// 输出验证
secondMap.forEach((key, employees) ->
System.out.println(key + " → " + employees));
}
}输出示例:
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
立即学习“Java免费学习笔记(深入)”;
DEPA → [Employee{id=1, name='aa'}, Employee{id=2, name='bb'}]
DEPC → [Employee{id=3, name='cc'}]
DEPD → [Employee{id=4, name='dd'}]
DEPAK → [Employee{id=5, name='A1'}, Employee{id=6, name='A2'}, Employee{id=7, name='A3'}, Employee{id=8, name='A4'}, Employee{id=9, name='A5'}]⚠️ 注意事项:
flatMapping是 Java 9 引入的 API,若项目受限于 Java 8,可退化为Collectors.collectingAndThen(Collectors.toList(), list -> list.stream().flatMap(Collection::stream).collect(Collectors.toList())),但代码冗长且性能略低;entry.getValue().stream()是关键:必须将List<employee></employee>显式转为Stream<employee></employee>,才能被flatMapping正确扁平;- 若需保持插入顺序,可将
groupingBy替换为groupingBy(..., LinkedHashMap::new, ...);- 建议对
null键或空List做防御性检查(如Objects.nonNull(entry.getKey()) && !entry.getValue().isEmpty()),提升健壮性。
通过 flatMapping,我们精准实现了“键标准化 + 值扁平聚合”的双重目标,代码简洁、语义清晰,是 Java Streams 高级聚合操作的典型实践。

















