流是 從 源生成的 元素序列。
流是 從支持數據處理操作的 源生成的 元素序列。
數據處理操作 如filter、map、reduce、find、match、sort等。
流操作有兩個重要的特點:
- 流水線
- 內部迭代
集合與流區別
粗略地說,集合與流之間的差異就在於什么時候進行計算。集合是一個內存中的數據結構,它包含數據結構中目前所有的值——集合中的每個元素都得先算出來才能添加到集合中。(
相比之下,流則是在概念上固定的數據結構(你不能添加或刪除元素),其元素則是按需計算的。
有點抽象類比為生產手機的流水線吧:集合是一堆生產好的手機,想放進去一個手機,那么這個手機必須生產好的。流是在流水線上的還未生產好的手機,流水線上不能拿走一個,也不能隨意放上去一個,流水線上會有一些操作。
遍歷
流只能遍歷一遍!
List<String> title = Arrays.asList("Java8", "In", "Action");
Stream<String> s = title.stream();
s.forEach(System.out::println); //成功遍歷
s.forEach(System.out::println);//java.lang.IllegalStateException:流已被操作或關閉
集合:外部迭代
流:內部迭代 內部迭代時,項目可以透明地並行處理,或者用更優化的順序進行處理。
流操作
List<String> names = menu.stream()
.filter(d -> d.getCalories() > 300)
.map(Dish::getName)
.limit(3)
.collect(toList());
你可以看到兩類操作:
-
filter、map和limit可以連成一條流水線;
-
collect觸發流水線執行並關閉它。
中間操作
中間操作返回的還是流,例如上面代碼的filter、map。除非流水線上觸發一個終端操作,否則中間操作不會執行任何處理——它們很懶。
利用流的延遲性質進行的優化:
- 這是因為limit操作和一種稱為短路的技巧。
- 盡管filter和map是兩個獨立的操作,但它們合並到同一次遍歷中了(我們把這種技術叫作循環合並)。
終端操作
終端操作會從流的流水線生成結果。其結果是任何不是流的值。流操作中可以據此判斷一個操作是中間操作還是終端操作。
long count = menu.stream()
.filter(d -> d.getCalories() > 300)
.distinct()
.limit(3)
.count();//流水線中最后一個操作count返回一個long,這是一個非Stream的值。
使用流
- 一個數據源(如集合)
- 一個中間操作鏈,形成一條流的流水線
- 一個終端操作,執行流水線,並能生成結果
所以
-
流是“從支持數據處理操作的源生成的一系列元素”。
-
流利用內部迭代:迭代通過filter、map、sorted等操作被抽象掉了。
-
流操作有兩類:中間操作和終端操作。
-
filter和map等中間操作會返回一個流,並可以鏈接在一起。可以用它們來設置一條流水線,但並不會生成任何結果。
-
forEach和count等終端操作會返回一個非流的值,並處理流水線以返回結果。
-
流中的元素是按需計算的。