棧長面試會經常問 Java 8 map 和 flatMap 的區別,大部分人都答不上來,會用 map 的都不多,還有一部分人甚至都不知道這兩個玩意是幹嘛用的,有的還以為我問 HashMap 和 FlatMap。。
這裡所問的 map 和 flatMap 並不是集合,它們都是 Stream 流接口中的方法,如果你沒用過,我估計在座的各位也有點暈,那麼今天棧長就給大家掃個盲,以實際案例來剖析這兩個玩意,讓你面試的時候再也不怕問了!
如圖所示:
在 Java 8 Stream(流)接口中有 8 個特別有意思的方法,其實就是分為兩大類:
現在知道這兩個玩意的來路了吧?!
其中,xxToXxx 就是轉換為不同的類型的流。另外,Stream 系列我之前寫過一個專題了,這裡不再展開,不懂的關注公眾號Java技術棧,然後在公眾號 Java 教程菜單中閱讀。
mapmap 方法的作用:
對流中的每個元素進行轉換
比如現在有一個 List<String> 集合:
private static List<String> LIST = Arrays.asList("https://", "www", ".", "javastack", ".", "cn");我想讓每個元素後面都加上 "---":
/**
* map 轉換
* @author: 棧長
* @from: 公眾號Java技術棧
*/
private static void map() {
List<String> mapList = LIST.stream().map(e -> e.concat("---")).collect(Collectors.toList());
mapList.forEach(System.out::print);
System.out.println("\nmap list size: " + mapList.size());
System.out.println();
}1)先把 List 轉換為 Stream;
2)調用 Stream.map 方法對 Stream 中的每個元素再封裝操作一遍;
3)把 Stream<Stream> 轉換為 List;
輸出結果:
=====map list===== https://---www---.---javastack---.---cn--- map list size: 6
結果符合預期。
另外,我將 Java 8知識點我也整理到了小程序,都是面試常考的,大家可以在Java面試庫小程序在線刷題。
如果 List 中的元素都是整數型:
private static List<String> NUMBERS_LIST = Arrays.asList("22", "19", "89", "90");那麼就可以 直接使用內置的 mapToXxx 方法,這裡以 mapToLong 演示:
/**
* mapToLong 轉換
* @author: 棧長
* @from: 公眾號Java技術棧
*/
private static void mapToLong() {
System.out.println("=====map to long list=====");
List<Long> longList = NUMBERS_LIST.stream().mapToLong(Long::valueOf).boxed().collect(Collectors.toList());
longList.forEach(System.out::println);
System.out.println("map to long list size: " + longList.size());
System.out.println();
}1)先把 List 轉換為 Stream;
2)調用 Stream.mapToLong 方法把流轉換為 LongStream 類型;
3)調用 LongStream.boxed 方法收集為 Stream<Long> 類型;
4)把 Stream<Long> 轉換為 List;
輸出結果:
=====map to long list===== 22 19 89 90 map to long list size: 4
當然這個使用 map 也能實現,但使用 mapToXxx 可以將原始流(Stream)轉換為 XxxStream:
XxxStream 可以有更多基於整數型的功能,比如快速對元素進行匯總(sum)、求最大數(max)、最小數(min)等等,如果要涉及到元素計算,使用 mapToXxx 會更香。
如源碼所示:
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
LongStream mapToLong(ToLongFunction<? super T> mapper);map 和 mapToXxx 的返回類型是不一樣的。
本文所有完整示例原始碼已經上傳:
https://github.com/javastacks/javastack
flatMapflatMap 方法的作用:
flat 是平鋪的意思,flatMap 即對流中每個元素進行平鋪後,形成多個流合在一起
比如現在有 3 個字符串數組:
String[] arr1 = {"https://", "www", ".", "javastack", ".", "cn"};
String[] arr2 = {"公眾號", ":", "Java技術棧"};
String[] arr3 = {"作者", ":", "棧長"};現在直接轉換為 Stream:
System.out.println("=====arrays list=====");
List<String[]> list = Stream.of(arr1, arr2, arr3).collect(Collectors.toList());
list.forEach(System.out::print);
System.out.println("\narrays list size: " + list.size());
System.out.println();結果輸出:
=====arrays list===== [Ljava.lang.String;@21b8d17c[Ljava.lang.String;@6433a2[Ljava.lang.String;@5910e440 arrays list size: 3
沒錯,是 3 個數組元素。
再來看使用 flatMap 方法的效果:
System.out.println("=====flatmap list=====");
List<String> mapList = list.stream().flatMap(Arrays::stream).collect(Collectors.toList());
mapList.forEach(System.out::print);
System.out.println("\nflatmap list size: " + mapList.size());
System.out.println();結果輸出:
=====flatmap list===== https://www.javastack.cn公眾號:Java技術棧作者:棧長 flatmap list size: 12
元素大小變成了 12,把 3 個數組流中的元素全部平鋪合到一個流中了,然後流中總共為 12 個元素。
這裡我用的數組類型,如果是多個 List<String> 類型也是可以的,其底層也是數組,只要能將元素轉換成流都是可以的。
總結map 是對流元素進行轉換,flatMap 是對流中的元素(數組)進行平鋪後合併,即對流中的每個元素平鋪後又轉換成為了 Stream 流。
來看下兩個方法的源碼:
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);其參數是不一樣的,map 前、後的每個元素都是 R 類型,flatMap 前、後的每個元素由原來的 R 類型都變成了 Stream 類型。
再小小總結下:
map 適用於對每個元素進行簡單的轉換,flatMap 適用於對數組流進行平鋪後合併,兩個方法的應用場景不一樣。
所以,你學廢了嗎?趕緊用在項目中吧,提升自己的硬實力,讓同事對你刮目相看!再囉嗦一句,對 Java 8 新增的知識點還不會用的可以關注公眾號:Java技術棧,在後臺回覆:java,Java 8+ 系列教程我都寫了一堆了。
本文所有完整示例原始碼已經上傳:
https://github.com/javastacks/javastack
歡迎 Star 學習,後面 Java 示例都會在這上面提供!