map实现一对一转换,输出流元素数不变;flatMap实现一对多映射加扁平化,返回Stream<R>并自动合并子流,需预处理null避免NPE。

Java 中函数式接口本身不直接处理集合映射或扁平化,真正起作用的是 Stream API 基于这些接口构建的操作链。map 和 flatMap 的行为由它们接受的函数式接口(Function<T,R> 和 Function<T,Stream<R>>)定义,但执行逻辑在 Stream 内部完成。
map 依赖 Function 实现一对一转换
map 接收一个 Function<T,R>,对每个元素做确定性变换,输出与输入数量一致的新流。
- 适合字段提取、格式转换、类型包装等场景,比如
user.getName()或s.length() - 若映射函数返回 null,结果流中对应位置就是 null(除非后续 filter 掉)
- 不能用于展开嵌套结构——它不会改变元素个数,也不会生成流
flatMap 依赖 Function> 实现一对多+扁平化
flatMap 要求函数返回 Stream<R>,它先映射出多个子流,再把它们合并成一个流。
- 典型用法:二维列表展平
nested.stream().flatMap(List::stream) - 字符串拆词
lines.stream().flatMap(s -> Arrays.stream(s.split(" "))) - 关联展开(用户→地址列表 → 所有地址)
- 关键细节:返回空流(如
Stream.empty())会被自然跳过,不影响结果
处理 Optional 时 flatMap 天然适配
Optional 的 stream() 方法返回 0 或 1 个元素的流,和 flatMap 完美配合。
立即学习“Java免费学习笔记(深入)”;
- 错误写法:
users.stream().map(u -> u.getEmail())→ 得到Stream<Optional<String>> - 正确写法:
users.stream().flatMap(u -> u.getEmail().stream())→ 直接得到Stream<String>,null 邮箱自动被过滤 - 无需手动判空或调用
isPresent(),语义更清晰
安全使用 flatMap 必须预处理 null
flatMap 的映射函数若对 null 调用 .stream() 会触发 NullPointerException。
- 推荐组合:先
filter(Objects::nonNull),再map取字段,再filter字段非空,最后flatMap - 单步写法:
list.stream().flatMap(item -> Optional.ofNullable(item).map(Item::getTags).orElse(Collections.emptyList()).stream()) - 避免在 lambda 内直接调用可能为 null 的方法链,比如
item.getTags().stream()


















