🎯 1. flatMap()
到底是啥?
flatMap()
是 Stream
里的中间操作,它的作用可以分两步理解:
- 第一步:对流里的每个元素,先**映射(转换)**成一个
Stream
。 - 第二步:把多个子流拍平成一个大的扁平流。
简单记忆:
map()
是一对一,flatMap()
是一对多。
🛠️ 2. 基础用法拆解
来看个例子:
List<String> list = List.of("Hello World", "Java Stream");
List<String> result = list.stream()
.map(s -> s.split(" ")) // 转成 String[] 流
.flatMap(Arrays::stream) // 拍平成单层流
.collect(Collectors.toList());
System.out.println(result);
✅ 执行过程解析
步骤 | 操作 | 结果 |
---|---|---|
🎯 map() |
每个元素转成数组 | [["Hello", "World"], ["Java", "Stream"]] |
🔥 flatMap() |
拍平成单层流 | ["Hello", "World", "Java", "Stream"] |
🔍 3. map()
vs flatMap()
的区别
我们用个更直观的对比例子:
List<String> list = List.of("a,b,c", "d,e,f");
// map()
List<String[]> mapResult = list.stream()
.map(s -> s.split(",")) // 每个元素变成 String[]
.collect(Collectors.toList());
System.out.println(mapResult);
// 输出: [[a, b, c], [d, e, f]] (嵌套数组)
// flatMap()
List<String> flatMapResult = list.stream()
.flatMap(s -> Arrays.stream(s.split(",")))
.collect(Collectors.toList());
System.out.println(flatMapResult);
// 输出: [a, b, c, d, e, f] (扁平化的一层)
✅ 总结:
功能 | map() |
flatMap() |
---|---|---|
结果 | 返回嵌套结构(Stream<Stream> 、List<List> 等) |
返回单层扁平结构 |
常见用途 | 单层对象转换 | 嵌套结构拍平、集合嵌套处理 |
结果类型 | Stream<T[]> / Stream<List> |
Stream<T> |
示例转换 | "A B" → ["A", "B"] | [["A", "B"], ["C", "D"]] → ["A", "B", "C", "D"] |
🔥 4. 高阶实战场景
🎯 4.1. 嵌套集合扁平化
List<List<Integer>> numbers = List.of(
List.of(1, 2, 3),
List.of(4, 5, 6),
List.of(7, 8, 9)
);
List<Integer> flatList = numbers.stream()
.flatMap(List::stream)
.collect(Collectors.toList());
System.out.println(flatList);
// 输出: [1, 2, 3, 4, 5, 6, 7, 8, 9]
🚀 4.2. 字符串拆分
假设我们有一组句子,想拆成单词:
List<String> sentences = List.of("Java is cool", "Stream API is powerful");
List<String> words = sentences.stream()
.flatMap(s -> Arrays.stream(s.split(" ")))
.collect(Collectors.toList());
System.out.println(words);
// 输出: [Java, is, cool, Stream, API, is, powerful]
🔥 4.3. 模拟 SQL JOIN
我们模拟多表连接(类似 SQL 的笛卡尔积):
List<String> names = List.of("Tom", "Jerry", "Mike");
List<String> hobbies = List.of("Coding", "Gaming", "Reading");
List<String> results = names.stream()
.flatMap(name -> hobbies.stream().map(hobby -> name + " loves " + hobby))
.collect(Collectors.toList());
results.forEach(System.out::println);
输出:
Tom loves Coding
Tom loves Gaming
Tom loves Reading
Jerry loves Coding
Jerry loves Gaming
Jerry loves Reading
Mike loves Coding
Mike loves Gaming
Mike loves Reading
🔥 5. Optional
配合 flatMap()
Optional
也有 flatMap()
!特别适合处理嵌套 Optional:
Optional<String> optionalName = Optional.of("Java");
Optional<String> upperName = optionalName
.flatMap(name -> Optional.of(name.toUpperCase()));
System.out.println(upperName.orElse("No Name"));
// 输出: JAVA
✅ 如果用 map()
:
Optional<Optional<String>> nestedOptional = optionalName.map(name -> Optional.of(name.toUpperCase()));
System.out.println(nestedOptional);
// 输出: Optional[Optional[JAVA]] (嵌套了两层)
🎉 6. 常见坑 & 注意事项
1️⃣ 避免空指针
如果 flatMap()
操作的是嵌套集合,务必确保子集合不为 null
:
List<List<String>> data = List.of(
List.of("Java", "Python"),
null // ❗️注意这里有null
);
List<String> result = data.stream()
.filter(Objects::nonNull) // 先过滤掉null
.flatMap(list -> list == null ? Stream.empty() : list.stream())
.collect(Collectors.toList());
System.out.println(result);
2️⃣ 性能考虑
flatMap()
频繁拍平大数据集合时性能可能受影响,考虑分批次处理,或者用 parallelStream()
。
3️⃣ 嵌套层级太多
如果嵌套层次太多(List<List<List<T>>>
),可以链式多次 flatMap()
:
List<List<List<String>>> deepNestedList = List.of(
List.of(List.of("A", "B"), List.of("C")),
List.of(List.of("D", "E"))
);
List<String> flatResult = deepNestedList.stream()
.flatMap(List::stream)
.flatMap(List::stream)
.collect(Collectors.toList());
System.out.println(flatResult);
// 输出: [A, B, C, D, E]
🎁 7. 终极总结
特点 | map() |
flatMap() |
---|---|---|
转换关系 | 一对一转换 | 一对多(Stream 扁平化) |
结果类型 | Stream<Stream<T>> |
Stream<T> |
常用场景 | 数据转换,简单映射 | 嵌套集合、字符串拆解 |
Optional 嵌套处理 | 返回嵌套 Optional | 解开嵌套 Optional |
🌟 总结
通过本文的学习,我们深入了解了 flatMap()
在 Java Stream 中的强大功能。它不仅能够处理多层嵌套数据、拆分字符串、模拟 SQL JOIN
,更能让你的代码更加简洁优雅,避免冗余的嵌套结构。
无论你是数据处理,还是解决复杂的集合操作,掌握 flatMap()
都将是你提升编码能力的关键一步。希望通过本文,大家能够更高效地利用这个工具,优化自己的代码结构,让代码不仅“能用”,更要“好用”。
如果你在学习过程中有任何疑问,或者有更多 flatMap()
的应用场景,欢迎在评论区留言,我们一起讨论!别忘了点赞、收藏和分享给更多需要的朋友哦!