在 Java 中,flatMap
是 Stream API
(Java 8+)中的一个重要方法,用于将嵌套的集合结构“扁平化”,或者将多个流合并为一个流。它的核心思想是**“先映射(Map),后扁平化(Flatten)”**。
1. flatMap 的核心作用
- 解决嵌套集合问题:当数据源是嵌套结构(如
List<List<T>>
)时,flatMap
可以将嵌套的集合“打平”成单层流。 - 一对多映射:将每个元素转换为多个新元素,并将所有结果合并成一个新的流。
2. flatMap vs. map
-
map
:将每个元素映射为另一个元素,结果仍是一一对应。List<String> words = Arrays.asList("Hello", "World"); List<Integer> lengths = words.stream().map(s -> s.length()) // 转换为每个字符串的长度.collect(Collectors.toList()); // 结果:[5, 5]
-
flatMap
:将每个元素映射为一个流,并将所有流合并为一个流。List<List<Integer>> nestedList = Arrays.asList(Arrays.asList(1, 2),Arrays.asList(3, 4) ); List<Integer> flatList = nestedList.stream().flatMap(list -> list.stream()) // 将每个 List<Integer> 转换为流,合并所有流.collect(Collectors.toList()); // 结果:[1, 2, 3, 4]
3. 经典使用场景
场景 1:拆分字符串并合并
List<String> lines = Arrays.asList("Hello World", "Java Programming");
List<String> words = lines.stream().flatMap(line -> Arrays.stream(line.split(" "))) // 拆分每个字符串为单词流.collect(Collectors.toList());
// 结果:["Hello", "World", "Java", "Programming"]
场景 2:处理嵌套集合
List<List<String>> nestedLists = Arrays.asList(Arrays.asList("A", "B"),Arrays.asList("C", "D")
);
List<String> mergedList = nestedLists.stream().flatMap(Collection::stream) // 等价于 list -> list.stream().collect(Collectors.toList());
// 结果:["A", "B", "C", "D"]
场景 3:Optional 的 flatMap
Optional<String> optionalValue = Optional.of("Hello");
Optional<Character> firstChar = optionalValue.flatMap(s -> s.isEmpty() ? Optional.empty() : Optional.of(s.charAt(0)));
// 结果:Optional['H']
4. 底层原理
flatMap
接收一个函数(Function<T, Stream<R>>
),该函数将每个元素转换为一个流。- 所有生成的流会被合并成一个最终的流。
- 如果某个元素映射后返回
null
或空流,它会被自动忽略。
5. 注意事项
- 避免深度嵌套:过度使用
flatMap
可能导致代码可读性下降。 - 延迟执行:与所有流操作一样,
flatMap
是延迟执行的,只有在终止操作(如collect
)触发时才会处理数据。 - 并行流兼容:
flatMap
可以安全用于并行流,但需确保函数是线程安全的。
6. 总结
- 用途:解决嵌套集合、一对多映射、流合并。
- 核心逻辑:
map
+flatten
(映射后扁平化)。 - 适用场景:处理复杂数据结构(如 JSON 嵌套、数据库关联查询结果)时非常高效。
如果结合 Java 的 Stream API
,flatMap
能让代码更简洁且更具表达力。