🎯 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()
的應用場景,歡迎在評論區留言,我們一起討論!別忘了點贊、收藏和分享給更多需要的朋友哦!