最近看到一篇講stream
語法的文章,學習Java
中map()
和flatMap()
方法之間的區別。
雖然看起來這兩種方法都做同樣的事情,都是做的映射操作,但實際上差之毫厘謬以千里。
通過演示Demo中的代碼可以了解map()
和flatMap()
的具體功能差異。
- 首先來一段簡單的
stream
語法foreach
方法的用法
演示Demo:
List<String> funs = Arrays.asList("F", "U", "N");
funs.stream().forEach(x -> output(x));
控制台輸出:
INFO-> 當前用戶:fv,IP:10.60.192.21,工作目錄:/Users/fv/Documents/workspace/fun/,系統編碼格式:UTF-8,系統Mac OS X版本:10.15.7
F
U
N
Process finished with exit code 0
map方法
map()
是一個中間操作,這意味着它返回Stream
對象。
- 先來一個簡單
演示Demo:
List<String> funs = Arrays.asList("F", "U", "N");
funs.stream().map(x->x+"001").forEach(x->output(x));
控制台輸出:
INFO-> 當前用戶:fv,IP:10.60.192.21,工作目錄:/Users/fv/Documents/workspace/fun/,系統編碼格式:UTF-8,系統Mac OS X版本:10.15.7
INFO-> f
INFO-> u
INFO-> n
INFO-> F001
INFO-> U001
INFO-> N001
java.util.stream.ReferencePipeline$3@27ae2fd0
java.util.stream.ReferencePipeline$3@29176cc1
Process finished with exit code 0
- 再來一個復雜的
演示Demo:
List<String> fun1 = Arrays.asList("one", "two", "three");
List<String> fun2 = Arrays.asList("four", "five", "six");
List<List<String>> nestedList = Arrays.asList(fun1, fun2);
nestedList.stream().map(x -> {
return x.stream().map(a -> a.toUpperCase());
}).forEach(x -> output(x));
控制台輸出:
INFO-> 當前用戶:fv,IP:10.60.192.21,工作目錄:/Users/fv/Documents/workspace/fun/,系統編碼格式:UTF-8,系統Mac OS X版本:10.15.7
INFO-> java.util.stream.ReferencePipeline$3@45018215
INFO-> java.util.stream.ReferencePipeline$3@30b7c004
顯然,在最后一步輸出的時候,x
是一個stream
的對象,而不是一個list
對象。
當我們嘗試從List<List<String>>
獲取值進行操作時,map()
無法如預期一樣工作,需要進行修改才能從嵌套的List<List<String>>
對象獲取字符串值。
如下:
List<String> fun1 = Arrays.asList("one", "two", "three");
List<String> fun2 = Arrays.asList("four", "five", "six");
List<List<String>> nestedList = Arrays.asList(fun1, fun2);
nestedList.stream().map(x -> {
return x.stream().map(a -> a.toUpperCase());
}).forEach(x ->x.forEach(a->output(a)));
控制台輸出:
INFO-> 當前用戶:fv,IP:10.60.192.21,工作目錄:/Users/fv/Documents/workspace/fun/,系統編碼格式:UTF-8,系統Mac OS X版本:10.15.7
INFO-> ONE
INFO-> TWO
INFO-> THREE
INFO-> FOUR
INFO-> FIVE
INFO-> SIX
Process finished with exit code 0
flatMap方法
讓我們在上述代碼中將map()
更改為flatMap()
,然后查看輸出。
- 先來一個簡單
演示Demo:
List<String> fun1 = Arrays.asList("one", "two", "three");
List<String> fun2 = Arrays.asList("four", "five", "six");
List<List<String>> nestedList = Arrays.asList(fun1, fun2);
nestedList.stream().flatMap(x -> x.stream()).map(x->x.toUpperCase()).forEach(x -> output(x));
控制台輸出:
INFO-> 當前用戶:fv,IP:10.60.192.21,工作目錄:/Users/fv/Documents/workspace/fun/,系統編碼格式:UTF-8,系統Mac OS X版本:10.15.7
INFO-> ONE
INFO-> TWO
INFO-> THREE
INFO-> FOUR
INFO-> FIVE
INFO-> SIX
Process finished with exit code 0
相當於在.flatMap(x -> x.stream())
這個時候我們把x.stream()
返回的stream
對象合並成了一個新的stream
對象。這一點在Stream
類的方法注釋中找到了印證。
/**
·····
* @return the new stream
*/
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
Java 8 map()與flatMap()
map()
和flatMap()
方法都可以應用於Stream<T>
和Optional<T>
對象。並且都返回Stream<R>
或Optional <U>
對象。區別在於map()
操作為每個輸入值生成一個輸出值,而flatMap()
操作為每個輸入值生成任意數量(零個或多個)的輸出值。
在flatMap()
中,每個輸入始終是一個集合,可以是List
或Set
或Map
。
map()
操作采用一個方法,該方法針對輸入流中的每個值調用,並生成一個結果值,該結果值返回至stream
。
flatMap()
操作采用的功能在概念上消耗一個集合對象並產生任意數量的值。但是在Java中方法返回任意數目的值很麻煩,因為方法只能返回void
或一個對象。
演示Demo:
List<String> fun1 = Arrays.asList("one", "two", "three");
List<String> fun2 = Arrays.asList("four", "five", "six");
Stream.of(fun1,fun2).flatMap(List::stream).forEach(Output::output);
控制台輸出:
INFO-> 當前用戶:fv,IP:10.60.192.21,工作目錄:/Users/fv/Documents/workspace/fun/,系統編碼格式:UTF-8,系統Mac OS X版本:10.15.7
INFO-> one
INFO-> two
INFO-> three
INFO-> four
INFO-> five
INFO-> six
Process finished with exit code 0
公眾號FunTester首發,原創分享愛好者,騰訊雲和掘金社區首頁推薦,知乎七級原創作者,歡迎關注、交流,禁止第三方擅自轉載。