1. 前言
我在 Java 8 Stream API中的 map 和flatMap 中講述了Java8 Stream API中 map
操作和 flatMap
操作的區(qū)別博脑。然后有小伙伴告訴我 peek
操作 也能實現(xiàn)元素的處理虐译。但是你知道 map
和 peek
的區(qū)別嗎白华? map
我們在開頭文章已經講過了长豁,你可以去詳細了解一下它荤崇,本文將重點講解一下 peek
操作瘦棋。
2. peek
peek
操作接收的是一個 Consumer<T>
函數(shù)澄成。顧名思義 peek 操作會按照 Consumer<T>
函數(shù)提供的邏輯去消費流中的每一個元素吹榴,同時有可能改變元素內部的一些屬性亭敢。
這里我們要提一下這個 Consumer<T>
以理解 什么時消費。
2.1 什么是消費 (Consumer)
package java.util.function;
import java.util.Objects;
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
// 嵌套accept , 順序為先執(zhí)行 accept 后執(zhí)行參數(shù)里的 after.accpet
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
Consumer<T>
是一個函數(shù)接口图筹。一個抽象方法 void accept(T t)
意為接受一個 T
類型的參數(shù)并將其消費掉帅刀。其實消費給我的感覺就是 “用掉” ,自然返回的就是 void
远剩。 通晨勰纾“用掉” T
的方式為兩種:
-
T 本身的 void 方法 比較典型的就是
setter
。 -
把 T 交給其它接口(類)的 void 方法進行處理 比如我們經常用的打印一個對象
System.out.println(T)
2.2 peek 操作演示
Stream<String> stream = Stream.of("hello", "felord.cn");
stream.peek(System.out::println);
如果你測試了上面給出的代碼你會發(fā)現(xiàn)民宿,壓根不會按照邏輯跑娇妓。這是為啥子呢? 這是因為流的生命周期有三個階段:
- 起始生成階段活鹰。
- 中間操作會逐一獲取元素并進行處理哈恰。 可有可無。所有中間操作都是惰性的志群,因此着绷,流在管道中流動之前,任何操作都不會產生任何影響锌云。
- 終端操作荠医。通常分為 最終的消費 (
foreach
之類的)和 歸納 (collect
)兩類。還有重要的一點就是終端操作啟動了流在管道中的流動桑涎。
所以應該改成下面:
Stream<String> stream = Stream.of("hello", "felord.cn");
List<String> strs= stream.peek(System.out::println).collect(Collectors.toLIst());
比如下圖彬向,我們給圓球加了一個框:
3. peek VS map
peek
操作 一般用于不想改變流中元素本身的類型或者只想操作元素的內部狀態(tài)時;而 map
則用于改變流中元素本身類型攻冷,即從元素中派生出另一種類型的操作娃胆。這是他們之間的最大區(qū)別。
那么 peek 實際中我們會用于哪些場景呢等曼?比如對 Stream<T>
中的 T
的某些屬性進行批處理的時候用 peek
操作就比較合適里烦。 如果我們要從 Stream<T>
中獲取 T
的某個屬性的集合時用 map
也就最好不過了凿蒜。
4. 總結
我們今天了解 Stream
的 peek
操作,同時也回顧了 Stream
的生命周期胁黑。也順帶對 Consumer<T>
函數(shù)進行了講解废封。而且 和 map
相互做了比較,對各自的使用場景又做了說明丧蘸。相信看過本文后你對它們會有更深的理解漂洋。
關注公眾號:碼農小胖哥,獲取更多資訊