Java-stream(1) Stream基本概念 & Stream介面
Java8 集合中的 Stream 相當於高階版的 Iterator,他可以通過 Lambda 表示式對集合進行各種非常便利、高效的聚合操作(Aggregate Operation),或者大批量資料操作 (Bulk Data Operation)
Stream 就如同一個迭代器(Iterator),單向,不可往復,資料只能遍歷一次,遍歷過一次後即用盡了,就好比流水從面前流過,一去不復返
函式式的解決方案解開了程式碼細節和業務邏輯的耦合,類似於sql語句,表達的是"要做什麼"而不是"如何去做",使程式設計師可以更加專注於業務邏輯,寫出易於理解和維護的程式碼
一、基本概念
1.1 Stream 操作分類
(圖片來源:極客時間-《java效能調優實戰》第6講)
我們通常還會將中間操作稱為懶操作,也正是由這種懶操作結合終結操作、資料來源構成的處理管道(Pipeline),實現了 Stream 的高效
1.2 Stream 主要架構類關係
二、Stream介面
2.1 概述(介面文件)
什麼是stream?
是一個支援序列/並行的聚合操作的元素佇列。為了進行計算,組建了一個 stream管道(pipeline),一個流管道由一個源(可能是陣列、集合、建構函式、I/O流等)、0到多箇中間操作(intermediate operations)和終結操作(terminal operation)組成。
stream有哪些特點?
-》流是惰性的,只有在啟動終結操作時才對源資料執行計算,只執行中間操作的時候是不會觸發流計算的,並且僅在需要時才使用源元素。
-》集合和stream雖然在表面有一些相似之處,但是他兩的側重點是不一樣的。集合主要是對元素的管理和訪問。相比之下,stream不提供直接訪問或者操作元素的方法,而是關注於宣告性地描述元素的聚合和計算操作,然而,如果所提供的流操作不提供所需的功能,則可以使用這些操作來執行受控遍歷。
-》如果stram popeline在操作過程中對源資料進行了修改操作會導致不可預知的報錯
-》引數會去呼叫函式介面(Function)或者通常使用lambda表示式引用,所以這些引數必須“非空”
-》在stream中資料從源到終結只會被執行一次,不可以重複運算元據,如果有重複使用的情況會丟擲 IllegalStateException 異常(由於一些流操作可能返回其接收器而不是新的流物件,因此可能不可能在所有情況下檢測重用)
-》stream有一個close()方法,還有實現了AutoCloseable介面(BaseStream繼承),但是大多數stream例項在使用完後不需要關閉,通常,只有源為IO通道的流才需要關閉。大多數流由集合、陣列或生成器組成,這些函式不需要特殊的資源管理
-》流管道可以序列執行資料,可以並行執行,通過paralle()方法去選擇不同的執行方式
2.2 一些常用方法
filter()
作用:中間-無狀態操作,對流資料進行過濾,返回滿足入參條件的資料
入參:Predicate<? super T> predicate 資料的過濾條件
出參:Stream:返回一個新的符合條件的Stream 流資料
舉例:過濾出 小於3 的元素
public static void main(String[] args) {
List<Integer> list = Stream.of(1, 2, 3, 4).filter(p -> p < 3).collect(Collectors.toList());
System.out.println(list);
}
輸出:[1, 2]
map()
作用:中間-無狀態操作,內部通過函式的形式對流資料進行一系列操作,返回函式結果集
入參:Function<? super T, ? extends R> mapper:操作函式
出參:Stream :返回一個新的函式處理結果集的流資料
舉例:將每個元素 +1
public static void main(String[] args) {
List<Integer> list = Stream.of(1, 2, 3, 4).map(p -> p + 1).collect(Collectors.toList());
System.out.println(list);
}
輸出:[2, 3, 4, 5]
distinct()
作用:
中間-有狀態操作,對當前流資料進行元素去重操作(通過equals()方法判斷),返回一個由不同元素組成的流資料,對於有序流,不同元素的選擇是穩定的(對於重複的元素,保留遇到的第一個出現的元素),對於無序流,不提供穩定性保證。如果是在並行管道(paralle pipeline)中,保持流資料的排序穩定性是比較昂貴的(要求當前操作充當一個完整的屏障,具有大量的緩衝開銷)。
一般情況下業務程式碼中是不需要保持排序穩定性的,是有無需流資料來源(generate())或者通過unordered()方法刪除排序約束可以更好的提高在並行管道中的執行效率。如果必須要做到排序的穩定性,最好切換到順序執行來提高效能。
入參:無入參,對當前流資料進行去重操作(this)
出參:Stream:去重後的一個新的流資料
舉例:將元素去重
public static void main(String[] args) {
List<Integer> list = Stream.of(1, 2, 4, 4).distinct().collect(Collectors.toList());
System.out.println(list);
}
sorted()
作用:中間-有狀態操作,對當前流資料進行自然排序(按照compareTo()規則排序),如果當前流資料沒有實現Comparable介面的話會丟擲 ClassCastException 異常。同樣,對於有序流,排序是穩定的。對於無序流,不提供穩定性保證。
入參:無入參,對當前流資料進行排序操作(this)
出參:Stream:排序後的一個新的流資料
備註:該方法還提供了過載方法,入參為Comparator介面物件,這個方法根據Comparator提供的規則來進行排序。
舉例:對元素進行排序
public static void main(String[] args) {
List<Integer> list = Stream.of(1, 3, 4, 2).sorted().collect(Collectors.toList());
System.out.println(list);
}
輸出:[1, 2, 3, 4]
peek()
作用:
中間-無狀態操作,對流資料進行一些操作,但是它只是對Stream中的元素進行某些操作(比如輸出之類),但是操作之後的資料並不返回到Stream中,所以返回的還是原來的元素,不會像map()一樣返回一個新的型別的流資料,通常會作為debug列印中間資料使用。
這裡要注意的是,如果流資料是個實體物件的話,peek()可以通過呼叫實體物件的setter方法對其屬性值進行改變——也就是說peek()可會流資料進行修改操作,其他方法是不具備的(會建立一個新的物件作為返回結果)。
入參:Consumer<? super T> action:對當前流資料的操作函式
出參:Stream:當前流資料
備註:map()和peek()的區別詳解移步:https://www.cnblogs.com/flydean/p/java-8-stream-peek.html
舉例:輸出每個元素值
public static void main(String[] args) {
List<Integer> list = Stream.of(1, 2, 3, 4).peek(p -> System.out.println("輸出:p = " + p)).collect(Collectors.toList());
System.out.println(list);
}
輸出:
輸出:p = 1
輸出:p = 2
輸出:p = 3
輸出:p = 4
[1, 2, 3, 4]
此外stream介面還提供了例如limit(限定流資料的長度),min(返回小元素),max(返回最大元素)等方法,這裡就不一一展開說明了,其原理都是相似的。
三、擴充套件
擴充套件一:Predicate介面
Predicate是個斷言式介面,其引數是<T,boolean>,也就是給一個引數T,返回boolean型別的結果。跟Function一樣,Predicate的具體實現也是根據傳入的lambda表示式來決定的。
boolean test(T t);
擴充套件二:排序穩定性
假定在一個待排序的序列中,存在多個相同的元素,若經過排序操作,這些元素的相對次序不變,則成為這種演算法是穩定的,否則就是不穩定的。
eg. 在原序列中,node1==node2 && node1在node2之前
排序後:如node1在node2之前並且無論執行多少次都是這樣,則認為這種演算法是穩定的,否則是不穩定的。
寫在最後 歡迎關注微信公眾號【小肖愛吃肉】和你一起記錄生活的小美好
相關文章
- java-Stream流Java
- Java-Stream流方法學習及總結Java
- Oracle Stream(1)--Streams概述Oracle
- NODE Stream流總結(1)
- stream
- 使用dataX-stream2stream/stream2mysql/mysql2mysql/mysql2streamMySql
- Java8新特性探索之Stream介面Java
- Java StreamJava
- Stream APIAPI
- elysia stream
- Stream流
- Java8之Stream-函式式介面Java函式
- Stream 流模組
- Java 8 StreamJava
- ORACLE STREAM ERROROracleError
- restart oracle streamRESTOracle
- Java Lambda StreamJava
- [Java]Stream用法Java
- spark stream初探Spark
- Oracle simple streamOracle
- centos stream 8CentOS
- 聊聊 Redis StreamRedis
- Stream流求和
- Stream瞭解
- Node.js 中的一股清流:理解 Stream(流)的基本概念Node.js
- Java Stream 詳解Java
- Java Stream流使用Java
- Stream聚合函式函式
- 【java】Stream的使用Java
- nodeJS之流streamNodeJS
- Oracle stream案例分享Oracle
- stream配置總結
- oracle stream pool sizeOracle
- spel和stream todo
- stream流各種
- Java 16 中新增的 Stream 介面的一些思考Java
- [Javascript] Refactor blocking style code to stream style for fetching the stream dataJavaScriptBloC
- Oracle Stream實戰(1)—測試環境介紹Oracle