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

性能篇:解密Stream,提升集合遍歷效率的秘訣!

開(kāi)發(fā) 前端
用事實(shí)說(shuō)話,我們看到其實(shí)使用 Stream 未必可以使系統(tǒng)性能更佳,還是要結(jié)合應(yīng)用場(chǎng)景進(jìn)行選擇,也就是合理地使用 Stream。總的來(lái)說(shuō),Stream 是一個(gè)強(qiáng)大而靈活的工具,但并不是適用于所有場(chǎng)景。在選擇使用 Stream 時(shí),我們需要根據(jù)實(shí)際情況進(jìn)行權(quán)衡和取舍。

大家好,我是小米,一個(gè)熱愛(ài)技術(shù)分享的小伙伴。今天我們來(lái)聊一聊 Java 中的 Stream,以及如何通過(guò) Stream 來(lái)提高遍歷集合的效率。

什么是Stream?

在開(kāi)始深入討論之前,我們先來(lái)了解一下什么是 Stream。

Stream 是 Java 8 中引入的一種新的抽象概念,用于處理數(shù)據(jù)序列。它為我們提供了一種更加便捷、高效的方式來(lái)操作集合數(shù)據(jù),實(shí)現(xiàn)了函數(shù)式編程的特性。在之前的 Java 版本中,我們通常使用迭代器或者循環(huán)來(lái)處理集合,代碼顯得冗長(zhǎng)且難以閱讀。而引入 Stream 后,我們可以采用聲明式的方式描述數(shù)據(jù)的處理流程,使代碼更加簡(jiǎn)潔、清晰。

Stream 的本質(zhì)是一種數(shù)據(jù)流,它不是一種數(shù)據(jù)結(jié)構(gòu),因此不會(huì)改變?cè)械臄?shù)據(jù)集合。相反,它提供了一系列的中間操作和終端操作,這些操作可以被串聯(lián)起來(lái)形成一條處理流水線。中間操作用于對(duì)數(shù)據(jù)進(jìn)行轉(zhuǎn)換和處理,而終端操作則觸發(fā)整個(gè)處理流程的執(zhí)行,產(chǎn)生最終的結(jié)果。

使用 Stream,我們可以輕松進(jìn)行各種操作,如篩選、映射、過(guò)濾、排序等,而無(wú)需手動(dòng)編寫繁瑣的迭代代碼。這種聲明式的編程風(fēng)格不僅提高了代碼的可讀性,還有助于并行處理,充分發(fā)揮多核 CPU 的性能優(yōu)勢(shì)。

以下是一個(gè)簡(jiǎn)單的代碼示例,演示了使用Stream對(duì)集合進(jìn)行過(guò)濾、映射和打印操作的好處:

圖片圖片

這個(gè)簡(jiǎn)單的示例展示了Stream的優(yōu)勢(shì),實(shí)際應(yīng)用中,Stream還可以進(jìn)行更復(fù)雜的操作,如分組、排序等,為集合處理提供了更多靈活性。

Stream操作分類 

在使用 Stream 進(jìn)行集合操作時(shí),我們通常將其分為兩種操作:中間操作和終端操作。

中間操作是在數(shù)據(jù)源上進(jìn)行的轉(zhuǎn)換和處理,但并不立即觸發(fā)流的遍歷。這些操作包括 filter、map、distinct 等。通過(guò) filter 我們可以輕松篩選出符合條件的元素,而 map 則用于轉(zhuǎn)換元素,使得處理過(guò)程更為靈活。

圖片圖片

在上述示例中,filter 用于選擇偶數(shù),map 則將這些偶數(shù)平方,形成了中間操作的鏈?zhǔn)秸{(diào)用。

終端操作是觸發(fā)流的遍歷并產(chǎn)生最終結(jié)果的操作,結(jié)束流的處理。這些操作包括 forEach、collect、reduce 等。通過(guò) collect 我們可以將流中的元素收集到一個(gè)新的集合中。

圖片圖片

在這個(gè)示例中,collect 將處理后的結(jié)果收集到一個(gè)新的列表中,結(jié)束了整個(gè)流的處理過(guò)程。

Stream源碼實(shí)現(xiàn)

Stream 的源碼實(shí)現(xiàn)是 Java 8 中引入的一項(xiàng)復(fù)雜而精妙的特性,它為處理集合數(shù)據(jù)提供了一種全新的方式。在深入探討 Stream 的源碼實(shí)現(xiàn)之前,我們首先需要了解幾個(gè)關(guān)鍵的類和接口,它們構(gòu)成了 Stream 操作的基礎(chǔ)結(jié)構(gòu)。

首先,BaseStream 接口是 Stream API 中的基礎(chǔ),它定義了一些基本的操作,例如串行執(zhí)行和并行執(zhí)行。這個(gè)接口為不同類型的 Stream,如 Stream、IntStream、DoubleStream 等提供了一致的接口定義,使得操作在不同類型的流之間能夠得到復(fù)用。

接著,AbstractPipeline 類是 Stream 的核心類之一,它封裝了操作的基本邏輯,包括遍歷、過(guò)濾等。這個(gè)類為具體的操作提供了抽象基類,簡(jiǎn)化了新操作的添加。它還定義了流水線的基本結(jié)構(gòu),使得我們能夠串聯(lián)多個(gè)操作形成一個(gè)完整的處理流程。

在針對(duì)對(duì)象引用流的處理中,ReferencePipeline 繼承自 AbstractPipeline,通過(guò)一系列方法(如 filter、map 等)生成不同類型的中間操作,形成操作鏈。而 Sink 類則負(fù)責(zé)接收元素并進(jìn)行實(shí)際的處理。這種流水線的設(shè)計(jì)充分體現(xiàn)了函數(shù)式編程的思想,每個(gè)操作都是不可變的,而且在進(jìn)行終端操作前,中間操作只是構(gòu)建了一個(gè)操作鏈而并未實(shí)際執(zhí)行。

在具體的操作實(shí)現(xiàn)中,以 filter 為例,通過(guò) ReferencePipeline 類的 filter 方法生成一個(gè)新的流水線,其中定義了過(guò)濾的邏輯,形成了一個(gè)中間操作。這個(gè)設(shè)計(jì)使得我們能夠以鏈?zhǔn)降姆绞浇M織多個(gè)操作,從而更加靈活地構(gòu)建數(shù)據(jù)處理流程。

Stream操作疊加源碼解析

在實(shí)際應(yīng)用中,我們常常需要對(duì)集合進(jìn)行多個(gè)操作,這時(shí)候就涉及到 Stream 操作的疊加。通過(guò)源碼解析,我們可以深入了解這一過(guò)程的執(zhí)行。

首先,讓我們看一下一個(gè)簡(jiǎn)單的例子:

圖片圖片

這個(gè)例子中,我們對(duì)數(shù)字集合進(jìn)行了篩選(filter)和映射(mapToInt)的兩個(gè)操作,然后求和。讓我們逐步分析這個(gè)過(guò)程。

filter操作

首先,filter 操作創(chuàng)建了一個(gè)新的 Stream,其中包含了符合條件的元素。這是通過(guò) ReferencePipeline 類的 filter 方法實(shí)現(xiàn)的,具體代碼如下:

圖片圖片

這段代碼展示了如何創(chuàng)建一個(gè)新的 Stream,其中的 Sink 對(duì)象通過(guò) predicate.test(u) 來(lái)判斷是否滿足條件,然后將符合條件的元素傳遞給下游。

mapToInt操作

接著,mapToInt 操作對(duì)上一個(gè)操作的結(jié)果進(jìn)行了映射,將元素乘以2。這是通過(guò) ReferencePipeline 類的 mapToInt 方法實(shí)現(xiàn)的,具體代碼如下:

圖片圖片

這段代碼展示了如何創(chuàng)建一個(gè)新的 IntStream,其中的 Sink 對(duì)象通過(guò) mapper.applyAsInt(u) 來(lái)進(jìn)行映射操作,將元素乘以2后傳遞給下游。

sum操作

最后,sum 操作對(duì)上一個(gè)操作的結(jié)果進(jìn)行了求和。這是通過(guò) SummingInt 類的 evaluate 方法實(shí)現(xiàn)的,具體代碼如下:

圖片圖片

這段代碼展示了如何對(duì)映射后的元素進(jìn)行求和操作,最終得到結(jié)果。

通過(guò)這個(gè)簡(jiǎn)單的例子,我們可以看到 Stream 操作的疊加是通過(guò)創(chuàng)建新的 Stream,并在每個(gè)操作的 Sink 中對(duì)元素進(jìn)行處理和傳遞的。這種鏈?zhǔn)秸{(diào)用的方式使得我們可以靈活組合多個(gè)操作,構(gòu)建出復(fù)雜的數(shù)據(jù)處理流程。

Stream并行處理源碼解析 

Stream 的一個(gè)顯著特點(diǎn)是能夠支持并行處理。在多核 CPU 的環(huán)境下,Stream 的并行迭代方式可以顯著提高性能。通過(guò)分析源碼,我們可以了解并行處理是如何實(shí)現(xiàn)的,以及在何種場(chǎng)景下使用更為合適。

首先,讓我們看一個(gè)簡(jiǎn)單的例子:

圖片圖片

在這個(gè)例子中,我們使用了 parallelStream() 方法將 Stream 轉(zhuǎn)換為并行流,然后進(jìn)行映射和求和操作。接下來(lái),我們將逐步分析這個(gè)過(guò)程。

parallelStream操作

首先,parallelStream() 方法是通過(guò) BaseStream 接口的 parallel() 方法實(shí)現(xiàn)的,具體代碼如下:

圖片圖片

這段代碼通過(guò) StreamSupport.stream(spliterator(), true) 來(lái)創(chuàng)建一個(gè)支持并行的 Stream。

并行處理的實(shí)現(xiàn)

在并行處理過(guò)程中,Stream 會(huì)被分割成多個(gè)子任務(wù),每個(gè)子任務(wù)在一個(gè)獨(dú)立的線程中執(zhí)行。這是通過(guò) ForkJoinTask 框架實(shí)現(xiàn)的,具體代碼如下:

圖片圖片

invoke() 方法用于執(zhí)行任務(wù),每個(gè)子任務(wù)都是一個(gè) ForkJoinTask,它們會(huì)在多個(gè)線程中同時(shí)執(zhí)行,最后將結(jié)果合并起來(lái)。

并行處理的Sink

在并行處理中,每個(gè)子任務(wù)都有自己的 Sink 對(duì)象,用于處理元素。這是通過(guò) ForkingSink 類實(shí)現(xiàn)的,具體代碼如下:

圖片圖片

ForkingSink 中的 accept() 方法用于接收元素,然后通過(guò) split() 方法將任務(wù)進(jìn)行分割。

通過(guò)這個(gè)簡(jiǎn)單的例子,我們可以看到 Stream 的并行處理是通過(guò) ForkJoin 框架實(shí)現(xiàn)的,每個(gè)子任務(wù)都在獨(dú)立的線程中執(zhí)行,最后將結(jié)果合并。這種方式能夠更好地利用多核 CPU 的性能,提高處理速度。

性能測(cè)試 

為了更直觀地比較兩者的性能,我們使用JMH(Java Microbenchmarking Harness)進(jìn)行測(cè)試。

以下是一個(gè)簡(jiǎn)單的示例代碼,假設(shè)我們有一個(gè)包含一系列數(shù)字的列表,我們將對(duì)這些數(shù)字進(jìn)行過(guò)濾,然后按照奇偶性進(jìn)行分組:

圖片圖片

測(cè)試結(jié)論:

圖片圖片

通過(guò)以上測(cè)試結(jié)果,我們可以看到:

  • 在循環(huán)迭代次數(shù)較少的情況下,常規(guī)的迭代方式性能反而更好;
  • 在單核 CPU 服務(wù)器配置環(huán)境中,也是常規(guī)迭代方式更有優(yōu)勢(shì);
  • 而在大數(shù)據(jù)循環(huán)迭代中,如果服務(wù)器是多核 CPU 的情況下,Stream 的并行迭代優(yōu)勢(shì)明顯。

所以我們?cè)谄綍r(shí)處理大數(shù)據(jù)的集合時(shí),應(yīng)該盡量考慮將應(yīng)用部署在多核 CPU 環(huán)境下,并且使用 Stream 的并行迭代方式進(jìn)行處理。

總結(jié) 

用事實(shí)說(shuō)話,我們看到其實(shí)使用 Stream 未必可以使系統(tǒng)性能更佳,還是要結(jié)合應(yīng)用場(chǎng)景進(jìn)行選擇,也就是合理地使用 Stream。

總的來(lái)說(shuō),Stream 是一個(gè)強(qiáng)大而靈活的工具,但并不是適用于所有場(chǎng)景。在選擇使用 Stream 時(shí),我們需要根據(jù)實(shí)際情況進(jìn)行權(quán)衡和取舍。

通過(guò)深入了解 Stream 的底層實(shí)現(xiàn),我們可以更好地運(yùn)用這一特性,提高代碼的可讀性和性能。

責(zé)任編輯:武曉燕 來(lái)源: 知其然亦知其所以然
相關(guān)推薦

2024-08-22 14:30:32

前端開(kāi)發(fā)VS Code

2020-06-04 16:57:07

移動(dòng)開(kāi)發(fā)互聯(lián)網(wǎng)實(shí)踐

2010-04-07 16:54:55

Oracle性能

2021-08-02 10:50:57

性能微服務(wù)數(shù)據(jù)

2012-06-12 09:46:20

虛擬化

2023-08-29 10:53:36

2009-02-23 15:55:29

ASP.NET.NET性能提升

2023-09-19 10:31:09

算法數(shù)據(jù)

2014-08-29 14:31:36

性能浪潮高性能

2012-06-14 16:21:24

LinuxLinus Torva

2020-05-07 10:25:13

工作效率遠(yuǎn)程辦公CIO

2024-09-21 11:35:40

2024-09-05 10:49:42

2012-11-21 17:35:21

Oracle技術(shù)嘉年華

2015-07-28 10:42:34

DevOpsIT效率

2020-10-15 09:10:02

MySQL性能優(yōu)化

2024-02-27 22:31:58

Golang日志優(yōu)化

2022-03-04 10:01:06

Bow IPUGraphcore

2012-03-12 13:35:10

開(kāi)發(fā)

2023-09-05 10:16:02

Java框架
點(diǎn)贊
收藏

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