Java8 Stream流學習筆記

流簡介

1.流是什么?

流到底是什么呢锭碳?簡短的定義就是“ 從支持數(shù)據(jù)處理操作生成的元素序列

  • 元素序列:就像集合一樣蹭秋,流也提供了一個接口,可以訪問特定元素類型的一組有序值年鸳。但流的目的在于表達計算,比如filter丸相、sorted和map搔确。集合講的事數(shù)據(jù),流講的是計算。
  • 源:流會使用一個提供數(shù)據(jù)的源膳算,如集合座硕、數(shù)組或者輸入/輸出資源。
  • 數(shù)據(jù)處理操作:流的數(shù)據(jù)處理功能支持類似于數(shù)據(jù)庫的操作涕蜂,以及函數(shù)式編程語言中的常用操作华匾,如filter、map机隙、reduce蜘拉、find、match有鹿、sort等旭旭。流操作可以順序執(zhí)行,也可以并行執(zhí)行葱跋。

流操作兩個重要的特點:

  1. 流水線:很多流操作本身會返回一個流持寄,這樣多個操作就可以鏈接起來,形成一個大的流水線娱俺。
  2. 內(nèi)部迭代:與使用迭代器顯示迭代的集合不同稍味,流的迭代操作是在背后進行的。

2.流與集合

流與集合之間的差異在于什么時候進行計算荠卷。

集合是一個內(nèi)存中的數(shù)據(jù)結(jié)構(gòu)模庐,它包含數(shù)據(jù)結(jié)構(gòu)中目前所有的值——集合中的每個元素都得先算出來才能添加到集合中。(集合中的每個元素都是放在內(nèi)存里的油宜,元素都得先算出來才能成為集合的一部分赖欣。)

流是在概念上固定的數(shù)據(jù)結(jié)構(gòu)(你不能添加或刪除元素),其元素則是按需計算的验庙。(流就像是一個延遲創(chuàng)建的集合:只有在消費者要求的時候才會計算值。)

2.1 流只能遍歷一次

==和迭代器類似社牲,流只能遍歷一次粪薛。遍歷完之后,我們就說這個流已經(jīng)被消費掉了搏恤。==

就比如下面這段代碼:

List<String> title = Arrays.asList("Java8","In","Action");
Stream<String> s = title.stream();
s.forEach(System.out::println);
//到這里就會報出異常:流已被操作或者關(guān)閉
s.forEach(System.out::println);

3. 外部迭代與內(nèi)部迭代

使用Collection接口需要用戶去做迭代(比如用for-each)违寿,這稱為外部迭代。相反熟空,Streams庫使用內(nèi)部迭代——它幫你把迭代做了藤巢,還把得到的流值存在了某個地方,你只要給出一個函數(shù)說要干什么就可以了息罗。

3.1 使用內(nèi)部迭代的原因

內(nèi)部迭代時掂咒,項目可以透明的并行處理,或者用更優(yōu)化的順序進行處理。

Streams庫的內(nèi)部迭代可以自動選擇一種適合硬件的數(shù)據(jù)表示和并行實現(xiàn)绍刮。與此相反温圆,一旦通過寫for-each而選擇了外部迭代,那你基本上就要自己管理所有的并行問題了(自己管理實際上意味著“某個良辰吉日我們會把它并行化”或者“開始了關(guān)于人物和synchronized的漫長二而艱苦的斗爭”孩革。)

差異對比.png

4. 流操作

可以連接起來的流操作稱為中間操作岁歉,關(guān)閉流的操作稱為終端操作

4.1 中間操作

諸如filter或sorted等中間操作會返回另一個流膝蜈。折讓多個操作可以鏈接起來形成一個查詢锅移。重要的是,==除非流水線上出發(fā)一個終端操作饱搏,否則中間操作不會執(zhí)行任何處理——它們很懶非剃。==

4.2 終端操作

終端操作會從流的流水線生成結(jié)果。其結(jié)果是任何不是流的值窍帝,比如List努潘、Integer,甚至是void坤学。

4.3 使用流

總而言之疯坤,流的使用一般包括三件事:

  1. 一個數(shù)據(jù)源(如集合)來執(zhí)行一個查詢;
  2. 一個中間操作鏈深浮,形成一條流的流水線压怠;
  3. 一個終端操作,執(zhí)行流水線飞苇,并能生成結(jié)果菌瘫;

中間操作:

操作 類型 返回類型 操作參數(shù) 函數(shù)描述符
filter 中間 Stream<T> Predicate<T> T -> boolean
map 中間 Stream<R> Funcation<T,R> T -> R
limit 中間 Stream<T>
sorted 中間 Stream<T> Comparator<T> (T布卡,T) -> int
distinct 中間 Stream<T>

終端操作:

操作 類型 目的
forEach 終端 消費流中的每個元素并對其應用Lambda雨让。這一操作返回void
count 終端 返回流中元素的個數(shù)。這一操作返回long
collect 終端 把流歸約成一個集合忿等,比如List栖忠、Map甚至是Integer。

小結(jié)

  1. 流是“ 從支持數(shù)據(jù)處理操作的源生成的一系列元素 ”贸街。
  2. 流利用內(nèi)部迭代:迭代通過filter庵寞、map、sorted等操作被抽象掉了薛匪。
  3. 流操作有兩類:中間操作和終端操作(也就終止操作)捐川。
  4. filter和map等中間操作會返回一個流,并可以鏈接在一起逸尖」帕ぃ可以把它們設(shè)置成一條流水線瘸右,但并不會生成任何結(jié)果。
  5. forEach和count等終端操作會返回一個非流的值渐白,并處理流水線以返回結(jié)果尊浓。
  6. 流中的元素是按需計算的。

使用流

1. 篩選和切片

1.1 謂詞篩選

Stream接口支持filter方法纯衍。該操作會接收一個謂詞(一個返回boolean的函數(shù))作為參數(shù)栋齿,并返回一個包括所有符合謂詞的元素的流

代碼示例:

List<Dish> vegetarianMenu = menu.stream().filter(Dish::isVegetarian).collect(toList());

1.2 篩選各異元素(去重)

==使用distinct()方法。==

1.3 截短流

流支持==limit(n)==方法襟诸,該方法會返回一個不超過給定長度的流瓦堵。所需的長度做為參數(shù)傳遞給limit。如果流是有序的歌亲,則最多會返回前n個元素菇用。

1.4 跳過元素

流支持==skip(n)==方法,該方法會返回一個扔4

掉前n個元素的流陷揪。如果流中元素不足n個惋鸥,則返回一個空值。

2. 映射

map

流支持map方法悍缠,它會接收一個函數(shù)做為參數(shù)卦绣。這個函數(shù)會被應用到每個元素上,并將其映射成一個新的元素 (使用映射一次飞蚓,是因為它和轉(zhuǎn)換類似滤港,但其中的細微差別在于它是“創(chuàng)建一個新版本”而不是去“修改”)。

flatMap

流支持flatMap方法趴拧,它的效果是溅漾,把一個流中的每個值都換成另一個流,然后把所有的流連接起來成為一個流著榴。

3.查找和匹配

3.1 檢查謂詞是否至少匹配一個元素

使用==anyMatch==方法添履。anyMatch方法返回一個boolean,因此是一個終端操作。

3.2 檢查謂詞是否匹配所有元素

使用==allMatch==方法。它的工作原理和anyMatch類似础嫡,但它會看看流中的元素是否都能匹配給定的謂詞。

其中和allMatch相對的是==noneMatch==。它可以確保流中沒有任何元素與給定的謂詞匹配瞎饲。

==注意:anyMatch口叙、allMatch和noneMatch這三個操作都用到了我們所謂的短路,這就是大家熟悉的Java中&&和||運算符短路在流中的版本嗅战。==

短路求值:

? 對于流而言妄田,某些操作(例如allMatch俺亮、anyMatch、noneMatch疟呐、findFirst和findAny)不用處理整個流就能得到結(jié)果脚曾。只要找到一個元素,就可以有結(jié)果了启具。同樣本讥,limit也是一個短路操作:它只需要創(chuàng)建一個給定大小的流,而用不著處理流中所有的元素鲁冯。在碰到無限大小的流的時候拷沸,這種操作就有用了:它們可以把無限流變成有限流

3.3 查找元素

==findAny==方法將返回當前流中的任意元素薯演。

其中這里涉及到Optional函數(shù)撞芍,以下為Optional簡介:

Optional<T>類(java.util.Optional)是一個容器類,代表一個值存在或不存在跨扮。findAny有時候可能什么元素都沒找到序无。Java8的庫設(shè)計人員引入了Optional<T>,這樣就不用返回眾所周知容易出問題的null了衡创。

Optional常用檢查方法說明:

  • isPresent()將在Optional包含值的時候返回true帝嗡,否則返回false。
  • ifPresent(Consumer<T> block)會在值存在的時候執(zhí)行給定的代碼塊钧汹。
  • T get()會在只存在時返回值丈探,否則拋出一個NoSuchElement異常。
  • T orElse(T other)會在值存在時返回值拔莱,否則返回一個默認值碗降。

4. 到目前為止所學習的中間操作和終端操作記錄

操作 類型 返回類型 操作參數(shù) 函數(shù)描述符
filter 中間 Stream<T> Predicate<T> T -> boolean
map 中間 Stream<R> Funcation<T,R> T -> R
limit 中間(有狀態(tài)-有界) Stream<T>
sorted 中間 Stream<T> Comparator<T> (T塘秦,T) -> int
distinct 中間(有狀態(tài)-無界) Stream<T>
skip 中間(有狀態(tài)-有界) Stream<T> long
flatMap 中間 Stream<R> Funcation<T,Stream<R>> T -> boolean
anyMatch 終端 boolean Predicate<T> T -> boolean
noneMatch 終端 boolean Predicate<T> T -> boolean
allMatch 終端 boolean Predicate<T> T -> boolean
findAny 終端 Optional<T>
findFirst 終端 Optional<T>
forEach 終端 void Consumer<T> T -> void
collect 終端 R Collector<T讼渊,A,R>
reduce 終端(有狀態(tài)-有界) Optional<T> BinaryOperator (T尊剔,T) -> T
count 終端 long
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末爪幻,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子须误,更是在濱河造成了極大的恐慌挨稿,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,807評論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件京痢,死亡現(xiàn)場離奇詭異奶甘,居然都是意外死亡,警方通過查閱死者的電腦和手機祭椰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,284評論 3 399
  • 文/潘曉璐 我一進店門臭家,熙熙樓的掌柜王于貴愁眉苦臉地迎上來疲陕,“玉大人,你說我怎么就攤上這事钉赁√阊辏” “怎么了?”我有些...
    開封第一講書人閱讀 169,589評論 0 363
  • 文/不壞的土叔 我叫張陵你踩,是天一觀的道長诅岩。 經(jīng)常有香客問我,道長姓蜂,這世上最難降的妖魔是什么按厘? 我笑而不...
    開封第一講書人閱讀 60,188評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮钱慢,結(jié)果婚禮上逮京,老公的妹妹穿的比我還像新娘。我一直安慰自己束莫,他們只是感情好懒棉,可當我...
    茶點故事閱讀 69,185評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著览绿,像睡著了一般策严。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上饿敲,一...
    開封第一講書人閱讀 52,785評論 1 314
  • 那天妻导,我揣著相機與錄音,去河邊找鬼怀各。 笑死倔韭,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的瓢对。 我是一名探鬼主播寿酌,決...
    沈念sama閱讀 41,220評論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼硕蛹!你這毒婦竟也來了醇疼?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,167評論 0 277
  • 序言:老撾萬榮一對情侶失蹤法焰,失蹤者是張志新(化名)和其女友劉穎秧荆,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體埃仪,經(jīng)...
    沈念sama閱讀 46,698評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡乙濒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,767評論 3 343
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了贵试。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片琉兜。...
    茶點故事閱讀 40,912評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖毙玻,靈堂內(nèi)的尸體忽然破棺而出豌蟋,到底是詐尸還是另有隱情,我是刑警寧澤桑滩,帶...
    沈念sama閱讀 36,572評論 5 351
  • 正文 年R本政府宣布梧疲,位于F島的核電站,受9級特大地震影響运准,放射性物質(zhì)發(fā)生泄漏幌氮。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,254評論 3 336
  • 文/蒙蒙 一胁澳、第九天 我趴在偏房一處隱蔽的房頂上張望该互。 院中可真熱鬧,春花似錦韭畸、人聲如沸宇智。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,746評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽随橘。三九已至,卻和暖如春锦庸,著一層夾襖步出監(jiān)牢的瞬間机蔗,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,859評論 1 274
  • 我被黑心中介騙來泰國打工甘萧, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留萝嘁,地道東北人。 一個月前我還...
    沈念sama閱讀 49,359評論 3 379
  • 正文 我出身青樓幔嗦,卻偏偏與公主長得像酿愧,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子邀泉,可洞房花燭夜當晚...
    茶點故事閱讀 45,922評論 2 361