flatMap的核心是“映射成流+合并”,即对每个元素应用返回Stream的函数,再将所有子流扁平合并为单个Stream<R>,惰性执行且禁止返回null。

flatMap 的核心不是“展开”本身,而是“映射成流 + 合并”。它不直接处理嵌套结构,而是让每个元素自己决定生成多少个新元素——通过返回一个 Stream。
flatMap 的执行逻辑很明确
它接收一个函数,这个函数对流中每个元素 T 执行一次,必须返回 Stream<R>(不能是 List、数组或 null);之后把所有子流里的 R 元素拼成一个统一的 Stream<R>;整个过程是惰性的,不触发计算,只构建流水线。
- 输入是 1 个元素 → 函数产出 0 个、1 个或多个 Stream<R> 元素
- 输出永远是 1 个扁平的 Stream<R>,没有层级嵌套
- 如果函数返回 null,运行时抛 NullPointerException;空集合(如 emptyList())返回 Stream.empty() 是安全的
常见展开场景与写法
多数时候你不是在“展开数据”,而是在“按关系提取并展平”:
-
List<List<String>> → Stream<String>:
.flatMap(List::stream) -
List<User> 中每个 User 有 List<Hobby> → Stream<Hobby>:
.flatMap(u -> u.getHobbies().stream())(注意判空) -
字符串列表拆词:
.flatMap(s -> Arrays.stream(s.split(" "))) -
一对多过滤(如 age 匹配学生):
ages.stream().flatMap(age -> students.stream().filter(s -> s.getAge() == age))
嵌套层级要逐级 flatMap
三级结构(比如 Country → City → District)不能一步到位,必须链式调用:
立即学习“Java免费学习笔记(深入)”;
- 先展开一级:
.flatMap(c -> c.getCities().stream()) - 再展开二级:
.flatMap(city -> city.getDistricts().stream()) - 中间任意环节若可能为 null,需兜底,例如:
.flatMap(c -> Optional.ofNullable(c.getCities()).orElse(List.of()).stream())
Map 或其他容器也能 flatMap
只要能转成 Stream,就可参与 flatMap。比如 Map<K, List<V>> 展开为 K-V 对:
- 先转 entry 流:
map.entrySet().stream() - 再 flatMap 每个 value:
.flatMap(e -> e.getValue().stream().map(v -> new SimpleEntry(e.getKey(), v)))


















