collectors.mapping用于分组后对每组元素映射转换,需嵌套在groupingby等收集器中使用;接收function和downstream收集器两个参数,支持字段提取、大小写转换、字符串拼接、dto构造等;需注意null处理及与tolist/toset/averagingint等下游收集器的组合用法。

Collectors.mapping 用于在分组(如 groupingBy)后,对每个分组内的元素进行映射转换,而不是先转换再分组。它必须配合其他收集器(如 groupingBy、toList、toSet 等)嵌套使用,不能单独用。
mapping 的基本用法:嵌套在 groupingBy 内部
mapping 接收两个参数:一个 Function(定义如何提取或转换元素),一个 downstream 收集器(定义转换后的结果如何收集)。常见场景是分组后只保留对象的某个字段,比如把 List
Map<string list>> deptToNames = users.stream()
.collect(Collectors.groupingBy(
User::getDept, // 分组键:部门名
Collectors.mapping(User::getName, // 对每组内每个 User 取 name
Collectors.toList()) // 收集为 List<string>
));</string></string>
支持复杂转换:结合方法引用或 Lambda
mapping 的第一个参数可以是任意 Function,不局限于 getter。例如转为大写、拼接字符串、构造新对象等:
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
- 转为大写姓名:
Collectors.mapping(u -> u.getName().toUpperCase(), Collectors.toList()) - 拼接姓名和年龄:
Collectors.mapping(u -> u.getName() + "(" + u.getAge() + ")", Collectors.toList()) - 构造 DTO:
Collectors.mapping(u -> new NameAge(u.getName(), u.getAge()), Collectors.toList())
注意空值与异常处理
如果 mapping 函数返回 null,且下游收集器是 toList/toSet,结果中会包含 null;若用 toMap 则可能抛 NullPointerException。安全做法是提前过滤或使用 Optional:
- 过滤掉 null 姓名:
stream.filter(u -> u.getName() != null).collect(...) - 用 Optional 处理:
Collectors.mapping(u -> Optional.ofNullable(u.getName()).orElse("未知"), Collectors.toList())
与其他下游收集器组合的常见模式
mapping 本质是“预处理”,下游可以灵活选择:
- 转为 Set 去重:
Collectors.mapping(User::getName, Collectors.toSet()) - 统计数量:
Collectors.mapping(u -> 1, Collectors.summingInt(Integer::intValue))(等价于 counting) - 求年龄平均值:
Collectors.mapping(User::getAge, Collectors.averagingInt(Integer::intValue)) - 二次分组:
Collectors.mapping(User::getRole, Collectors.groupingBy(Function.identity()))(每组内再按角色分)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










