stream and lambda(9) - 中間操作之map操作(map、flatmap)

語言: CN / TW / HK

map 操作算是比較常用的操作了,它可以將元素經過處理後輸出成另一個元素。這就和 java method 很像了,輸入參數,經過方法處理,輸出一個返回參數。

map

方法定義

<R> Stream<R> map(Function<? super T, ? extends R> mapper);

map 方法看起來就很簡潔明瞭,入參是 Function ,作用是 將元素 T 經過邏輯處理後轉換成 R 。當然,這個轉換過程中可做的東西就多了。比如類型轉換、屬性提取、邏輯運算、業務處理等。

使用舉例

public void mapTest() {
    Stream<Integer> of = Stream.of(1, 23, 4);
    List<String> result = of.map(i -> "my value is " + i).collect(Collectors.toList());
    System.out.println(result);
}

運行後輸出如下:

[my value is 1, my value is 23, my value is 4]

經過 map,我們將一個數字轉成了一大串的字符串。(小聲BB,這要是能把我的餘額 map(money -> 100 * money) 該有多好啊)

flatmap

方法定義

<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);

flatmap 就很容易讓人分不清和 map 的區別了。

首先先從名字上看,壓平了 map ?往死裏給我 map

還是從入參上來分析吧。經過 Function 運算,把元素轉化成一個 Stream 。瞭解了,和 map 的區別是, map 是把元素從 A 對象轉換成 B 對象,而 flatmap 是把元素從 A 對象轉換成流。

大致過程如下圖,這樣看你就明白是怎麼 壓平 了的了。

使用舉例

首先,我們還是看下 map ,然後再看 flatmap ,這樣才更容易對比理解。

先給定初始字符串數組:

String[] strs = {"this", "is", "flatmap"};
  1. 將三個字符串後加上空格依次打印
Arrays.stream(strs).map(str -> str + " ").forEach(System.out::print);

此時,對於三個元素,是轉換成了另一個字符串

  1. 將所有字母依次輸出

一般思路是將這三個字符串分割成單個字母進行輸出,我們嘗試一下下面的代碼

Arrays.stream(strs).map(str -> str.split("")).forEach(System.out::print);

此時,我們預期的是輸出 thisisflatmap ,但是實際上輸出的卻是 [Ljava.lang.String;@36b4cef0[Ljava.lang.String;@fad74ee[Ljava.lang.String;@1a1d6a08 。看來,輸出的並不是單個的字母,為什麼呢?

原因就在於, map 之後,字符串轉成了數組,所以輸出了數組。想要輸出單個字符怎麼辦? 把數組壓平(flat),把數組裏的元素壓出來

Arrays.stream(strs).map(str -> str.split("")).flatMap(Arrays::stream).forEach(System.out::print);

此時,輸出的就是 thisisflatmap 了。

當然,瞭解了 flatmap ,也可以這樣寫。

Arrays.stream(strs).flatMap(str -> Arrays.stream(str.split(""))).forEach(System.out::print);

總結

  • map 的本質就是傳入一個 Function ,將單個元素轉成另一個元素,然後將所有元素組成一個新的 Stream
  • flatmap 的本質是傳入一個 Function ,將單個元素轉成一個 Stream ,然後將多個 Stream 合併成一個新的 Stream
  • 如果還是有些迷糊,請看圖。

注:本文配套代碼可在 github 查看: stream-and-lambda