我們來詳細解釋一下 Java 8 Stream API 中的?flatMap
?操作。理解?flatMap
?的關鍵在于將其與?map
?操作進行對比。
??核心概念:??
??
map
?操作:??- 作用:將一個流中的每個元素??轉換??為另一個元素(類型可以不同)。
- 輸入:一個元素?
T
- 輸出:一個元素?
R
?(通過你提供的?Function<T, R>
?函數) - 結果流:一個包含所有轉換后元素?
R
?的流?Stream<R>
。 - ??特點:?? 輸入一個元素,輸出一個元素。輸入流中有 N 個元素,輸出流中也有 N 個元素(類型可能變了)。
??
flatMap
?操作:??- 作用:將一個流中的每個元素??轉換??為??零個、一個或多個新元素組成的流??,然后將所有這些生成的流??“扁平化”?? 連接成一個單一的流。
- 輸入:一個元素?
T
- 輸出:一個流?
Stream<R>
?(通過你提供的?Function<T, Stream<R>>
?函數) - 結果流:將每個輸入元素?
T
?產生的?Stream<R>
?中的所有元素??連接(展平)?? 起來形成的最終?Stream<R>
。 - ??特點:??
- 輸入一個元素,輸出一個??流??(包含零個、一個或多個元素)。
- 然后將所有輸出的流“拍扁”,合并成一個單一的流。
- 輸入流中有 N 個元素,輸出流中的元素個數可以是 0 到 M(M 是所有生成的流中元素的總和)。元素類型通常也會改變。
??為什么叫 “flatMap”???
- ??Map:?? 因為它像?
map
?一樣,對每個元素應用一個轉換函數。 - ??Flat:?? 因為它將轉換后產生的??嵌套結構(流中的流)?? “展平”(flatten)成一個單一的流。
??核心函數式接口:??
map
?使用?Function<T, R>
:?R apply(T t)
flatMap
?使用?Function<T, Stream<R>>
:?Stream<R> apply(T t)
?— ??注意返回值必須是?Stream
!??
??常見使用場景:??
??展平嵌套集合:?? 這是最經典的用法。
List<List<String>> nestedList = Arrays.asList(Arrays.asList("a", "b", "c"),Arrays.asList("d", "e"),Arrays.asList("f", "g", "h") );// 使用 map: 得到一個包含3個流的流 (Stream<Stream<String>>) Stream<Stream<String>> streamOfStreams = nestedList.stream().map(list -> list.stream());// 使用 flatMap: 得到一個包含所有字符串的單一流 (Stream<String>) Stream<String> flatStream = nestedList.stream().flatMap(list -> list.stream());List<String> flattenedList = flatStream.collect(Collectors.toList()); // flattenedList 結果為: ["a", "b", "c", "d", "e", "f", "g", "h"]
- 處理可能產生多個結果的元素:?? 例如,一個字符串數組,你想把每個字符串按空格分割成單詞。
List<String> lines = Arrays.asList("Hello world", "Java 8 Streams", "flatMap example");// 使用 map + split: 得到一個包含字符串數組的流 (Stream<String[]>) Stream<String[]> streamOfArrays = lines.stream().map(line -> line.split(" "));// 使用 flatMap + Arrays.stream(): 得到一個包含所有單詞的單一流 (Stream<String>) Stream<String> wordsStream = lines.stream().flatMap(line -> Arrays.stream(line.split(" ")));List<String> words = wordsStream.collect(Collectors.toList()); // words 結果為: ["Hello", "world", "Java", "8", "Streams", "flatMap", "example"]
總結?flatMap
:??
- ??目的:?? 處理那些一個輸入元素會映射到??多個輸出元素??(或者需要表示為流)的場景,并將這些輸出??平滑地合并??到最終的結果流中。
- ??關鍵:?? 你提供給?
flatMap
?的函數 (Function<T, Stream<R>>
) ??必須返回一個?Stream
?對象??。 - ??結果:?? 將輸入流中每個元素產生的所有?
Stream<R>
?的內容連接起來,形成一個單一的、連續的?Stream<R>
。 - ??效果:?? “展平”嵌套結構或一對多映射。
簡單來說,當你遇到類似“我有一個列表,里面的每個元素本身又是一個列表(或其他集合),我想把它們合并成一個大列表”或者“我有一個流,每個元素處理后會得到一組結果,我想把這些結果都收集到一個流里”的情況時,flatMap
?就是你的好幫手。
?