自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

看不懂同事的代碼?超強(qiáng)的 Stream 流操作姿勢(shì)還不學(xué)習(xí)一下

新聞 前端
我們都知道 Lambda 和 Stream 是 Java 8 的兩大亮點(diǎn)功能,在前面的文章里已經(jīng)介紹過(guò) Lambda 相關(guān)知識(shí),這次介紹下 Java 8 的 Stream 流操作。

我們都知道 Lambda 和 Stream 是 Java 8 的兩大亮點(diǎn)功能,在前面的文章里已經(jīng)介紹過(guò) Lambda 相關(guān)知識(shí),這次介紹下 Java 8 的 Stream 流操作。它完全不同于 java.io 包的 Input/Output Stream ,也不是大數(shù)據(jù)實(shí)時(shí)處理的 Stream 流。這個(gè) Stream 流操作是 Java 8 對(duì)集合操作功能的增強(qiáng),專(zhuān)注于對(duì)集合的各種高效、便利、優(yōu)雅的聚合操作。借助于 Lambda 表達(dá)式,顯著的提高編程效率可讀性。且 Stream 提供了并行計(jì)算模式,可以簡(jiǎn)潔的編寫(xiě)出并行代碼,能充分發(fā)揮如今計(jì)算機(jī)的多核處理優(yōu)勢(shì)。

1. Stream 流介紹

Stream 不同于其他集合框架,它也不是某種數(shù)據(jù)結(jié)構(gòu),也不會(huì)保存數(shù)據(jù),但是它負(fù)責(zé)相關(guān)計(jì)算,使用起來(lái)更像一個(gè)高級(jí)的迭代器。在之前的迭代器中,我們只能先遍歷然后在執(zhí)行業(yè)務(wù)操作,而現(xiàn)在只需要指定執(zhí)行什么操作, Stream 就會(huì)隱式的遍歷然后做出想要的操作。另外 Stream 和迭代器一樣的只能單向處理,如同奔騰長(zhǎng)江之水一去而不復(fù)返。

由于 Stream 流提供了惰性計(jì)算并行處理的能力,在使用并行計(jì)算方式時(shí)數(shù)據(jù)會(huì)被自動(dòng)分解成多段然后并行處理,最后將結(jié)果匯總。所以 Stream 操作可以讓程序運(yùn)行變得更加高效。

2. Stream 流概念

Stream 流的使用總是按照一定的步驟進(jìn)行,可以抽象出下面的使用流程。

數(shù)據(jù)源(source) -> 數(shù)據(jù)處理/轉(zhuǎn)換(intermedia) -> 結(jié)果處理(terminal )

2.1. 數(shù)據(jù)源

數(shù)據(jù)源(source)也就是數(shù)據(jù)的來(lái)源,可以通過(guò)多種方式獲得 Stream 數(shù)據(jù)源,下面列舉幾種常見(jiàn)的獲取方式。

 

  • Collection.stream(); 從集合獲取流。
  • Collection.parallelStream(); 從集合獲取并行流。
  • Arrays.stream(T array) or Stream.of(); 從數(shù)組獲取流。
  • BufferedReader.lines(); 從輸入流中獲取流。
  • IntStream.of() ; 從靜態(tài)方法中獲取流。
  • Stream.generate(); 自己生成流

 

2.2. 數(shù)據(jù)處理

數(shù)據(jù)處理/轉(zhuǎn)換(intermedia)步驟可以有多個(gè)操作,這步也被稱為intermedia(中間操作)。在這個(gè)步驟中不管怎樣操作,它返回的都是一個(gè)新的流對(duì)象,原始數(shù)據(jù)不會(huì)發(fā)生任何改變,而且這個(gè)步驟是惰性計(jì)算處理的,也就是說(shuō)只調(diào)用方法并不會(huì)開(kāi)始處理,只有在真正的開(kāi)始收集結(jié)果時(shí),中間操作才會(huì)生效,而且如果遍歷沒(méi)有完成,想要的結(jié)果已經(jīng)獲取到了(比如獲取第一個(gè)值),會(huì)停止遍歷,然后返回結(jié)果。惰性計(jì)算可以顯著提高運(yùn)行效率。

數(shù)據(jù)處理演示。

還看不懂同事的代碼?超強(qiáng)的 Stream 流操作姿勢(shì)還不學(xué)習(xí)一下

數(shù)據(jù)處理/轉(zhuǎn)換操作自然不止是上面演示的過(guò)濾 filter 和 map映射兩種,另外還有 map (mapToInt, flatMap 等)、 filter、 distinct、 sorted、 peek、 limit、 skip、 parallel、 sequential、 unordered 等。

2.3. 收集結(jié)果

結(jié)果處理(terminal )是流處理的最后一步,執(zhí)行完這一步之后流會(huì)被徹底用盡,流也不能繼續(xù)操作了。也只有到了這個(gè)操作的時(shí)候,流的數(shù)據(jù)處理/轉(zhuǎn)換等中間過(guò)程才會(huì)開(kāi)始計(jì)算,也就是上面所說(shuō)的惰性計(jì)算。結(jié)果處理也必定是流操作的最后一步。

常見(jiàn)的結(jié)果處理操作有 forEach、 forEachOrdered、 toArray、 reduce、 collect、 min、 max、 count、 anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 iterator 等。

下面演示了簡(jiǎn)單的結(jié)果處理的例子。

還看不懂同事的代碼?超強(qiáng)的 Stream 流操作姿勢(shì)還不學(xué)習(xí)一下

2.4. short-circuiting

有一種 Stream 操作被稱作 short-circuiting ,它是指當(dāng) Stream 流無(wú)限大但是需要返回的 Stream 流是有限的時(shí)候,而又希望它能在有限的時(shí)間內(nèi)計(jì)算出結(jié)果,那么這個(gè)操作就被稱為short-circuiting。例如 findFirst 操作。

3. Stream 流使用

Stream 流在使用時(shí)候總是借助于 Lambda 表達(dá)式進(jìn)行操作,Stream 流的操作也有很多種方式,下面列舉的是常用的 11 種操作。

3.1. Stream 流獲取

獲取 Stream 的幾種方式在上面的 Stream 數(shù)據(jù)源里已經(jīng)介紹過(guò)了,下面是針對(duì)上面介紹的幾種獲取 Stream 流的使用示例。

還看不懂同事的代碼?超強(qiáng)的 Stream 流操作姿勢(shì)還不學(xué)習(xí)一下

3.2. forEach

forEach 是 Strean 流中的一個(gè)重要方法,用于遍歷 Stream 流,它支持傳入一個(gè)標(biāo)準(zhǔn)的 Lambda 表達(dá)式。但是它的遍歷不能通過(guò) return/break 進(jìn)行終止。同時(shí)它也是一個(gè) terminal 操作,執(zhí)行之后 Stream 流中的數(shù)據(jù)會(huì)被消費(fèi)掉。

如輸出對(duì)象。

還看不懂同事的代碼?超強(qiáng)的 Stream 流操作姿勢(shì)還不學(xué)習(xí)一下

3.3. map / flatMap

使用 map 把對(duì)象一對(duì)一映射成另一種對(duì)象或者形式。

還看不懂同事的代碼?超強(qiáng)的 Stream 流操作姿勢(shì)還不學(xué)習(xí)一下

上面的 map 可以把數(shù)據(jù)進(jìn)行一對(duì)一的映射,而有些時(shí)候關(guān)系可能不止 1對(duì) 1那么簡(jiǎn)單,可能會(huì)有1對(duì)多。這時(shí)可以使用 flatMap。下面演示使用 flatMap把對(duì)象扁平化展開(kāi)。

還看不懂同事的代碼?超強(qiáng)的 Stream 流操作姿勢(shì)還不學(xué)習(xí)一下

3.4. filter

使用 filter 進(jìn)行數(shù)據(jù)篩選,挑選出想要的元素,下面的例子演示怎么挑選出偶數(shù)數(shù)字。

還看不懂同事的代碼?超強(qiáng)的 Stream 流操作姿勢(shì)還不學(xué)習(xí)一下

得到如下結(jié)果。

2,4,6,8,

3.5. findFirst

findFirst 可以查找出 Stream 流中的第一個(gè)元素,它返回的是一個(gè) Optional 類(lèi)型,如果還不知道 Optional 類(lèi)的用處,可以參考之前文章 Jdk14都要出了,還不能使用 Optional優(yōu)雅的處理空指針? 。

還看不懂同事的代碼?超強(qiáng)的 Stream 流操作姿勢(shì)還不學(xué)習(xí)一下

findFirst 方法在查找到需要的數(shù)據(jù)之后就會(huì)返回不再遍歷數(shù)據(jù)了,也因此 findFirst 方法可以對(duì)有無(wú)限數(shù)據(jù)的 Stream 流進(jìn)行操作,也可以說(shuō) findFirst 是一個(gè) short-circuiting 操作。

3.6. collect / toArray

Stream 流可以輕松的轉(zhuǎn)換為其他結(jié)構(gòu),下面是幾種常見(jiàn)的示例。

還看不懂同事的代碼?超強(qiáng)的 Stream 流操作姿勢(shì)還不學(xué)習(xí)一下

3.7. limit / skip

獲取或者扔掉前 n 個(gè)元素

還看不懂同事的代碼?超強(qiáng)的 Stream 流操作姿勢(shì)還不學(xué)習(xí)一下

3.8. Statistics

數(shù)學(xué)統(tǒng)計(jì)功能,求一組數(shù)組的最大值、最小值、個(gè)數(shù)、數(shù)據(jù)和、平均數(shù)等。

還看不懂同事的代碼?超強(qiáng)的 Stream 流操作姿勢(shì)還不學(xué)習(xí)一下

3.9. groupingBy

分組聚合功能,和數(shù)據(jù)庫(kù)的 Group by 的功能一致。

還看不懂同事的代碼?超強(qiáng)的 Stream 流操作姿勢(shì)還不學(xué)習(xí)一下

3.10. partitioningBy

還看不懂同事的代碼?超強(qiáng)的 Stream 流操作姿勢(shì)還不學(xué)習(xí)一下

3.11. 進(jìn)階 - 自己生成 Stream 流

還看不懂同事的代碼?超強(qiáng)的 Stream 流操作姿勢(shì)還不學(xué)習(xí)一下

上面的例子中 Stream 流是無(wú)限的,但是獲取到的結(jié)果是有限的,使用了 Limit 限制獲取的數(shù)量,所以這個(gè)操作也是 short-circuiting 操作。

4. Stream 流優(yōu)點(diǎn)

4.1. 簡(jiǎn)潔優(yōu)雅

正確使用并且正確格式化的 Stream 流操作代碼不僅簡(jiǎn)潔優(yōu)雅,更讓人賞心悅目。下面對(duì)比下在使用 Stream 流和不使用 Stream 流時(shí)相同操作的編碼風(fēng)格。

還看不懂同事的代碼?超強(qiáng)的 Stream 流操作姿勢(shì)還不學(xué)習(xí)一下

如果是使用 Stream 流操作。

還看不懂同事的代碼?超強(qiáng)的 Stream 流操作姿勢(shì)還不學(xué)習(xí)一下

4.2. 惰性計(jì)算

上面有提到,數(shù)據(jù)處理/轉(zhuǎn)換(intermedia) 操作 map (mapToInt, flatMap 等)、 filter、 distinct、 sorted、 peek、 limit、 skip、 parallel、 sequential、 unordered 等這些操作,在調(diào)用方法時(shí)并不會(huì)立即調(diào)用,而是在真正使用的時(shí)候才會(huì)生效,這樣可以讓操作延遲到真正需要使用的時(shí)刻。

下面會(huì)舉個(gè)例子演示這一點(diǎn)。

還看不懂同事的代碼?超強(qiáng)的 Stream 流操作姿勢(shì)還不學(xué)習(xí)一下

如果沒(méi)有 惰性計(jì)算,那么很明顯會(huì)先輸出偶數(shù),然后輸出 分割線。而實(shí)際的效果是。

分割線

2

4

6

可見(jiàn) 惰性計(jì)算 把計(jì)算延遲到了真正需要的時(shí)候。

4.3. 并行計(jì)算

獲取 Stream 流時(shí)可以使用 parallelStream 方法代替 stream 方法以獲取并行處理流,并行處理可以充分的發(fā)揮多核優(yōu)勢(shì),而且不增加編碼的復(fù)雜性。

下面的代碼演示了生成一千萬(wàn)個(gè)隨機(jī)數(shù)后,把每個(gè)隨機(jī)數(shù)乘以2然后求和時(shí),串行計(jì)算和并行計(jì)算的耗時(shí)差異。

還看不懂同事的代碼?超強(qiáng)的 Stream 流操作姿勢(shì)還不學(xué)習(xí)一下

得到如下輸出。

還看不懂同事的代碼?超強(qiáng)的 Stream 流操作姿勢(shì)還不學(xué)習(xí)一下

效果顯而易見(jiàn),代碼簡(jiǎn)潔優(yōu)雅。

5. Stream 流建議

5.1 保證正確排版

從上面的使用案例中,可以發(fā)現(xiàn)使用 Stream 流操作的代碼非常簡(jiǎn)潔,而且可讀性更高。但是如果不正確的排版,那么看起來(lái)將會(huì)很糟糕,比如下面的同樣功能的代碼例子,多幾層操作呢,是不是有些讓人頭大?

還看不懂同事的代碼?超強(qiáng)的 Stream 流操作姿勢(shì)還不學(xué)習(xí)一下

5.1 保證函數(shù)純度

如果想要你的 Stream 流對(duì)于每次的相同操作的結(jié)果都是相同的話,那么你必須保證 Lambda 表達(dá)式的純度,也就是下面亮點(diǎn)。

  • Lambda 中不會(huì)更改任何元素。
  • Lambda 中不依賴于任何可能更改的元素。

這兩點(diǎn)對(duì)于保證函數(shù)的冪等非常重要,不然你程序執(zhí)行結(jié)果可能會(huì)變得難以預(yù)測(cè),就像下面的例子。

還看不懂同事的代碼?超強(qiáng)的 Stream 流操作姿勢(shì)還不學(xué)習(xí)一下

 

責(zé)任編輯:張燕妮 來(lái)源: 今日頭條
相關(guān)推薦

2022-06-16 14:07:26

Java代碼代碼review

2022-07-26 14:38:08

JavaScriptWeb安全自動(dòng)化

2020-03-30 16:45:06

代碼寫(xiě)看不懂

2022-02-07 09:05:00

GitHub功能AI

2021-08-30 07:49:34

數(shù)據(jù)庫(kù)數(shù)倉(cāng)Doris

2019-12-09 08:29:26

Netty架構(gòu)系統(tǒng)

2021-12-09 11:59:49

JavaScript前端提案

2020-09-04 15:13:43

Java 8接口物流信息

2013-07-08 10:49:03

程序員代碼看懂代碼

2020-03-06 11:30:08

JavaGitHub編程

2019-10-24 08:56:38

語(yǔ)言代碼Java

2021-02-23 10:36:09

Linux命令kmdr

2022-12-12 07:40:36

服務(wù)器項(xiàng)目Serverless

2023-11-23 17:02:34

LinuxSED工具

2024-12-26 16:47:48

2023-06-30 08:01:04

Reactuse關(guān)鍵詞

2024-12-09 08:00:00

C++代碼

2014-03-12 09:25:33

產(chǎn)品經(jīng)理Startup

2017-09-19 15:45:39

2020-04-09 10:25:37

Redis分布式算法
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)