轉載請標明出處:http://blog.csdn.net/zhaoyanjun6/article/details/106389071
本文出自【趙彥軍的博客】
目錄
1、基礎概念
Java 8 API添加了一個新的抽象稱爲流Stream,可以讓你以一種聲明的方式處理數據。
Stream 使用一種類似用 SQL 語句從數據庫查詢數據的直觀方式來提供一種對 Java 集合運算和表達的高階抽象。
Stream API可以極大提高Java程序員的生產力,讓程序員寫出高效率、乾淨、簡潔的代碼。
這種風格將要處理的元素集合看作一種流, 流在管道中傳輸, 並且可以在管道的節點上進行處理, 比如篩選, 排序,聚合等。
元素流在管道中經過中間操作(intermediate operation)的處理,最後由最終操作(terminal operation)得到前面處理的結果。
如果你用過 rxjava ,入門就很簡單。
2、常見操作符
filter 過濾
var list = mutableListOf("b", "a", "d", "c")
ist.stream()
.filter {
it != "a" //輸出元素不是 a 的元素
}
.forEach {
Log.d("yanjun", it)
}
輸出結果:
D/yanjun: b
D/yanjun: d
D/yanjun: c
findFirst 查找第一個
var list = mutableListOf("b", "a", "d", "c")
var first = list.stream()
.findFirst() //查找第一個元素
.get()
Log.d("yanjun", first)
輸出結果:
D/yanjun: b
sorted 從小到大排序
var list2 = listOf(3, 1, 2)
list2.stream()
.sorted() //默認從小到大排序
.forEach {
Log.d("yanjun", it.toString())
}
輸出結果:
D/yanjun: 1
D/yanjun: 2
D/yanjun: 3
map 方法用於映射每個元素到對應的結果
var list = listOf(3, 1, 2)
list.stream()
.map {
it * 2 //所有元素都乘以 2
}
.forEach {
Log.d("yanjun", it.toString())
}
輸出結果:
D/yanjun: 6
D/yanjun: 2
D/yanjun: 4
limit 獲取指定數量的流
var list = listOf(3, 1, 2)
list.stream()
.limit(2) //只輸出前2個數據
.forEach {
Log.d("yanjun", it.toString())
}
輸出結果:
D/yanjun: 3
D/yanjun: 1
collect 將流轉換成集合和聚合元素
var list = listOf(3, 1, 2)
var list2 = list.stream()
.sorted() //排序 結果爲:1 2 3
.collect(Collectors.toList()) //把流數據轉換成 list
list2.forEach {
Log.d("yanjun", it.toString())
}
輸出結果:
D/yanjun: 1
D/yanjun: 2
D/yanjun: 3
average 求平均值
var list = listOf(3, 1, 2)
var value = list.average() //求平均值
Log.d("yanjun", value.toString())
輸出結果:
D/yanjun: 2.0
3、Stream 執行順序
數據流的鏈式調用是垂直執行的, 但並不是每個操作符都是垂直的,sorted是水平執行的。
爲什麼要設計成這樣呢?原因是出於性能的考慮。
例子1
var list = mutableListOf("b", "a", "d", "c")
list.stream()
.map {
Log.d("yanjun map", it)
it
}
.forEach {
Log.d("yanjun forEach", it)
}
輸出結果:
D/yanjun map: b
D/yanjun forEach: b
D/yanjun map: a
D/yanjun forEach: a
D/yanjun map: d
D/yanjun forEach: d
D/yanjun map: c
D/yanjun forEach: c
例子2
var list = mutableListOf("b", "a", "d", "c")
list.stream()
.map {
Log.d("yanjun map", it)
it
}
.sorted() //排序
.forEach {
Log.d("yanjun forEach", it)
}
輸出結果:
D/yanjun map: b
D/yanjun map: a
D/yanjun map: d
D/yanjun map: c
D/yanjun forEach: a
D/yanjun forEach: b
D/yanjun forEach: c
D/yanjun forEach: d
4、數據流複用問題
Java8 Stream 流是不能被複用的,一旦你調用任何終端操作,流就會關閉:
var list = mutableListOf("b", "a", "d", "c")
var stream = list.stream()
//流第一次被使用,使用完畢後,流被關閉,不能重複使用
stream.forEach {
Log.d("yanjun", it)
}
//流第二次被使用,會報異常
stream.forEach {
Log.d("yanjun", it)
}
報異常,程序出錯
5、並行流
集合支持parallelStream()方法來創建元素的並行流。或者你可以在已存在的數據流上調用中間方法parallel(),將串行流轉換爲並行流,這也是可以的。
var list = mutableListOf("b", "a", "d", "c")
list.parallelStream() //創建並行流
.map {
Thread.sleep(5000) //模擬耗時操作
Log.d("yanjun map", Thread.currentThread().name + " " + it)
it
}
.forEach {
Log.d("yanjun forEach", Thread.currentThread().name + " " + it)
}
輸出結果:
D/yanjun map: main d
D/yanjun forEach: main d
D/yanjun map: ForkJoinPool.commonPool-worker-1 a
D/yanjun map: ForkJoinPool.commonPool-worker-2 b
D/yanjun forEach: ForkJoinPool.commonPool-worker-1 a
D/yanjun forEach: ForkJoinPool.commonPool-worker-2 b
D/yanjun map: ForkJoinPool.commonPool-worker-3 c
D/yanjun forEach: ForkJoinPool.commonPool-worker-3 c
如您所見,並行流使用了所有的ForkJoinPool中的可用線程來執行流式操作。在持續的運行中,輸出結果可能有所不同,因爲所使用的特定線程是非特定的。
總結
- 無存儲:Stream是基於數據源的對象,它本身不存儲數據元素,而是通過管道將數據源的元素傳遞給操作。
- 函數式編程:對Stream的任何修改都不會修改背後的數據源,比如對Stream執行filter操作並不會刪除被過濾的元素,而是會產生一個不包含被過濾元素的新的Stream。
- 延遲執行:Stream的操作由零個或多箇中間操作(intermediate operation)和一個結束操作(terminal operation)兩部分組成。只有執行了結束操作,Stream定義的中間操作纔會依次執行,這就是Stream的延遲特性。
- 可消費性:Stream只能被“消費”一次,一旦消費就會失效。就像容器的迭代器那樣,想要再次遍歷必須重新生成一個新的Stream。