flatMap() 到底是啥?flatMap() 是 Stream 里的中间操作,它的作用可以分两步理解:
Stream。简单记忆:
map()是一对一,flatMap()是一对多。
来看个例子:
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"] |
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"] |
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]假设我们有一组句子,想拆成单词:
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]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 ReadingOptional 配合 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]] (嵌套了两层)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]特点 | map() | flatMap() |
|---|---|---|
转换关系 | 一对一转换 | 一对多(Stream 扁平化) |
结果类型 | Stream<Stream<T>> | Stream<T> |
常用场景 | 数据转换,简单映射 | 嵌套集合、字符串拆解 |
Optional 嵌套处理 | 返回嵌套 Optional | 解开嵌套 Optional |
通过本文的学习,我们深入了解了 flatMap() 在 Java Stream 中的强大功能。它不仅能够处理多层嵌套数据、拆分字符串、模拟 SQL JOIN,更能让你的代码更加简洁优雅,避免冗余的嵌套结构。
无论你是数据处理,还是解决复杂的集合操作,掌握 flatMap() 都将是你提升编码能力的关键一步。希望通过本文,大家能够更高效地利用这个工具,优化自己的代码结构,让代码不仅“能用”,更要“好用”。
如果你在学习过程中有任何疑问,或者有更多 flatMap() 的应用场景,欢迎在评论区留言,我们一起讨论!别忘了点赞、收藏和分享给更多需要的朋友哦!