流簡介
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í)行葱跋。
流操作兩個重要的特點:
- 流水線:很多流操作本身會返回一個流持寄,這樣多個操作就可以鏈接起來,形成一個大的流水線娱俺。
- 內(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的漫長二而艱苦的斗爭”孩革。)
4. 流操作
可以連接起來的流操作稱為中間操作岁歉,關(guān)閉流的操作稱為終端操作。
4.1 中間操作
諸如filter或sorted等中間操作會返回另一個流膝蜈。折讓多個操作可以鏈接起來形成一個查詢锅移。重要的是,==除非流水線上出發(fā)一個終端操作饱搏,否則中間操作不會執(zhí)行任何處理——它們很懶非剃。==
4.2 終端操作
終端操作會從流的流水線生成結(jié)果。其結(jié)果是任何不是流的值窍帝,比如List努潘、Integer,甚至是void坤学。
4.3 使用流
總而言之疯坤,流的使用一般包括三件事:
- 一個數(shù)據(jù)源(如集合)來執(zhí)行一個查詢;
- 一個中間操作鏈深浮,形成一條流的流水線压怠;
- 一個終端操作,執(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é)
- 流是“ 從支持數(shù)據(jù)處理操作的源生成的一系列元素 ”贸街。
- 流利用內(nèi)部迭代:迭代通過filter庵寞、map、sorted等操作被抽象掉了薛匪。
- 流操作有兩類:中間操作和終端操作(也就終止操作)捐川。
- filter和map等中間操作會返回一個流,并可以鏈接在一起逸尖」帕ぃ可以把它們設(shè)置成一條流水線瘸右,但并不會生成任何結(jié)果。
- forEach和count等終端操作會返回一個非流的值渐白,并處理流水線以返回結(jié)果尊浓。
- 流中的元素是按需計算的。
使用流
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 |