面試官:Java 8 map 和 flatMap 的區別?大部分人答不上來!

2021-12-24 IT服務圈兒
來源丨經授權轉自 Java技術棧(ID:javastack)背景

棧長面試會經常問 Java 8 map 和 flatMap 的區別,大部分人都答不上來,會用 map 的都不多,還有一部分人甚至都不知道這兩個玩意是幹嘛用的,有的還以為我問 HashMap 和 FlatMap。。

這裡所問的 map 和 flatMap 並不是集合,它們都是 Stream 流接口中的方法,如果你沒用過,我估計在座的各位也有點暈,那麼今天棧長就給大家掃個盲,以實際案例來剖析這兩個玩意,讓你面試的時候再也不怕問了!

如圖所示:

在 Java 8 Stream(流)接口中有 8 個特別有意思的方法,其實就是分為兩大類:

現在知道這兩個玩意的來路了吧?!

其中,xxToXxx 就是轉換為不同的類型的流。另外,Stream 系列我之前寫過一個專題了,這裡不再展開,不懂的關注公眾號Java技術棧,然後在公眾號 Java 教程菜單中閱讀。

map

map 方法的作用:

對流中的每個元素進行轉換

比如現在有一個 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

flatMap

flatMap 方法的作用:

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 示例都會在這上面提供!

相關焦點

  • 到處是map、flatMap,啥意思?
    用的最多的,就是map、flatMap之類的。但是其他小夥伴不願意了,雖然有的人感覺代碼變的容易懂了,但有更多的人感覺代碼變的很晦澀。那感覺就像是:脫了褲子放屁,多此一舉。這些函數的作用域,根據級別,我覺得可以分為三類。簡直是無所不在。
  • Java 8 Map,Filter和Collect示例
    與map類似,過濾器也是一個中間操作,這意味著您可以在調用過濾器後調用其他Stream方法。filter()方法也是惰性的,這意味著在調用reduce方法之前不會對它進行求值,它會在到達目標時立即停止。如何在Java 8中使用Map和Filter你需要一個很好的例子來理解這些概念。
  • JAVA map的用法/如何遍歷MAP
    :         String str = map.get("a").toString();       // 這樣獲取到str的值就是1;第四步:如果我們遍歷這個MAP,從中取得key和value怎麼辦,如下就可以:for(Object obj : map.keySet()){             Object value = map.get(obj );
  • Java map詳解-用法、遍歷、排序、常用API
    2、☞ 《Java面試手冊》.PDF    點擊查看Map用法類型介紹java 自帶了各種 Map 類,這些 Map 類可歸為三種類型:用於在應用程式中管理映射,通常在 java.util 程序包中實現 HashMap、Hashtable、Properties、LinkedHashMap
  • java 基礎 之 集合 Map
    //: containers/Maps.java// Things you can do with Maps.import java.util.concurrent.*;import java.util.*;import net.mindview.util.
  • Java冷門小技巧:如何使用Steam.map()轉換流?
    map()方法是一個中間操作。它返回一個流,該流包括將給定函數應用於流中每個元素的結果。以下代碼返回一個整數流,這是應用String.length()方法的結果。importjava.util.ArrayList;import java.util.List;import java.util.stream.Stream;publicclassJava8Map
  • java中關於Map的九大問題
    下面就以K和V來代表鍵和值,來說明一下java中關於Map的九大問題。  0、將Map轉換為List類型  在java中Map接口提供了三種集合獲取方式:Key set,,value set, and key-value set.。它們都可以通過構造方法或者addAll()方法來轉換為List類型。
  • Java集合List和Map面試題以及答案
    Set在數學上的意義就是集合的概念,他和List不一樣的是,不允許集合中的元素重複。所以存入的元素都必須定義equals()方法來確保對象的唯一性,Set接口有兩個實現來Hashset和TreeSet,其中TreeSet是實現了SortedSet接口的。
  • Map經典面試題,你遇到了嗎?
    依稀記得我當初面試遇到過兩道涉及到Map的面試題,當時是有點眼急,會,直接手寫代碼確實又不會了。  工作了一段時間,再看完Map,自己又重新溫習了一下這兩道面試題,難,不難,只在一瞬息。  map.containsKey(c)){ map.put(c, 1); }else{ Integer count = map.get(c); count++; map.put(c, count);
  • JAVA 8 OPTIONAL源碼及案例分析
    java.util.optional是從JDK 8開始引的類,Optional是一個包含了空值(NULL)或非空值(NOT NULL)的對象容器,用於判斷方法的返回類型是否有值,Optional的好處是可以避免由於NULL帶來的異常情況,如NullPointerException。
  • MapStruct:一款java對象轉換神器
    調用getter/setter方法手動硬編碼屬性賦值調用BeanUtil.copyProperties進行反射屬性賦值getter/setter手工硬編碼的方式相信很多 Java 開發同學都異常熟練,它的痛點也非常明顯,就是當一個類有幾十個屬性的時候,代碼編寫效率非常低下,而且醜陋,最重要的是,當新擴展一個欄位以後,往往容易忽略在 mapping convert 文件中添加相應的屬性映射,給業務帶來一定的潛在風險
  • 前端高頻面試考點--Set、Map、WeakSet 和 WeakMap區別
    WeakMap 的區別?>Set和Map主要的應用場景在於數組去重和數據存儲,Set是一種叫做集合的數據結構,Map是一種叫做字典的數據結構集合與字典的區別強引用和弱引用之間有什麼區別       javaScript中的大多數變量都保存著對一個對象的強引用
  • 從打牌到map-reduce工作原理解析
    找到工作後的一小段時間是清閒的,小史把新租房收拾利索後,就開始找同學小趙,小李和小王來聚會了。(注意,如果有兩幅完整的牌,那麼小趙手中的黑桃A一定不少於2張,因為其他人手中已經不可能有黑桃A了,圖中的數據只是演示。)
  • MapStruct的使用,java實體類的轉換
    可能還會涉及到類型的轉換,如果這樣就會導致滿屏幕的get set方法,不僅感覺很low,而且不符合軟體的精神——不要重複造輪子。下面給大家推薦一款比較好用的插件,他可以用來完成實體類之間的轉換工作,並且可以自定義轉換方法-MapStruct。
  • 【010期】JavaSE面試題(十):集合之Map
    3.底層是hash表,不保證有序(比如插入的順序);1.7版本:數組+鍊表1.8版本:數組+鍊表+紅黑樹HashMap在JDK1.7和JDK1.8中有哪些不同?HashMap使用的是懶加載,構造完HashMap對象後,只要不進行put 方法插入元素之前,HashMap並不會去初始化或者擴容table。
  • Java 8 中 Map 騷操作之 merge() 的用法
    2、☞ 《Java面試手冊》.PDF    點擊查看Java 8 最大的特性無異於更多地面向函數,比如引入了 lambda等,可以更好地進行函數式編程。前段時間無意間發現了 map.merge() 方法,感覺還是很好用的,此文簡單做一些相關介紹。首先我們先看一個例子。merge() 怎麼用?
  • Map和WeakMap
    ; map.has('1'); map.clear(); map.delete('1'); map.keys();map.values();Map和Object的主要區別:1.Object的鍵只能是字符串或者Symbol值,Map鍵可以是任意值;2.Map中的鍵值是有序的,先進的一直展示在前面,而Object中的鍵則不是有序的:
  • 黑馬程式設計師Java教程:Java基礎教程之MAP集合
    Java提供了專門的集合類用來存放這種對象關係的對象,即java.util.Map接口。我們通過查看Map接口描述,發現Map接口下的集合與Collection接口下的集合,它們存儲數據的形式不同,如下圖。
  • Java基礎知識點面試手冊(線程+JDK8)
    高並發編程多線程和單線程的區別和聯繫:答:在單核 CPU 中,將 CPU 分為很小的時間片,在每一時刻只能有一個線程在執行,是一種微觀上輪流佔用 CPU 的機制。多線程會存在線程上下文切換,會導致程序執行速度變慢,即採用一個擁有兩個線程的進程執行所需要的時間比一個線程的進程執行兩次所需要的時間要多一些。
  • Java中遍歷Map集合的五種方式
    作者:揚帆向海https://zhangxy.blog.csdn.net/article/details/113336560在java