1. 前言
你知道 map
和 peek
的區(qū)別嗎?本文將重點(diǎn)講解一下 peek
操作。
2. peek
peek
操作接收的是一個(gè) Consumer<T>
函數(shù)缸棵。顧名思義 peek 操作會(huì)按照 Consumer<T>
函數(shù)提供的邏輯去消費(fèi)流中的每一個(gè)元素,同時(shí)有可能改變?cè)貎?nèi)部的一些屬性。這里我們要提一下這個(gè) Consumer<T>
以理解 什么是消費(fèi)较性。
2.1 什么是消費(fèi) (Consumer)
package java.util.function;
import java.util.Objects;
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
// 嵌套accept , 順序?yàn)橄葓?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>
是一個(gè)函數(shù)接口用僧。一個(gè)抽象方法 void accept(T t)
意為接受一個(gè) T
類型的參數(shù)并將其消費(fèi)掉。其實(shí)消費(fèi)給我的感覺就是 “用掉” 赞咙,自然返回的就是 void
责循。通常“用掉” T
的方式為兩種:
-
T 本身的 void 方法 比較典型的就是
setter
攀操。 -
把 T 交給其它接口(類)的 void 方法進(jìn)行處理 比如我們經(jīng)常用的打印一個(gè)對(duì)象
System.out.println(T)
2.2 peek 操作演示
Stream<String> stream = Stream.of("hello", "felord.cn");
stream.peek(System.out::println);
如果你測(cè)試了上面給出的代碼你會(huì)發(fā)現(xiàn)院仿,壓根不會(huì)按照邏輯跑。這是為啥子呢速和?這是因?yàn)榱鞯纳芷谟腥齻€(gè)階段:
- 起始生成階段歹垫。
- 中間操作:會(huì)逐一獲取元素并進(jìn)行處理〉叻牛可有可無(wú)排惨。所有中間操作都是惰性的,因此碰凶,流在管道中流動(dòng)之前暮芭,任何操作都不會(huì)產(chǎn)生任何影響。
- 終端操作:通常分為 最終的消費(fèi) (
foreach
之類的)和 歸納 (collect
)兩類欲低。還有重要的一點(diǎn)就是終端操作啟動(dòng)了流在管道中的流動(dòng)谴麦。
所以應(yīng)該改成下面:
Stream<String> stream = Stream.of("hello", "felord.cn");
List<String> strs= stream.peek(System.out::println).collect(Collectors.toLIst());
3. peek VS map
peek
操作 一般用于不想改變流中元素本身的類型或者只想元素的內(nèi)部狀態(tài)時(shí);而 map
則用于改變流中元素本身類型伸头,即從元素中派生出另一種類型的操作匾效。這是他們之間的最大區(qū)別。那么 peek 實(shí)際中我們會(huì)用于哪些場(chǎng)景呢恤磷?比如對(duì) Collection<T>
中的 T
的某些屬性進(jìn)行批處理的時(shí)候用 peek
操作就比較合適面哼。如果我們要從 Collection<T>
中獲取 T
的某個(gè)屬性的集合時(shí)用 map
也就最好不過(guò)了。