《Java 8 in Action》Chapter 4:引入流

1. 流簡介

流是Java API的新成員,它容許你以聲明性方式處理數據集合(經過查詢語句來表達,而不是臨時編寫一個實現)。就如今來講,你能夠把它們當作遍歷數據集的高級迭代器。此外,流還能夠透明地並行處理。讓咱們來看一個實例返回低熱量(<400)的菜餚名稱:< p=""> java

Java7版本:
List<Dish> lowCaloricDishes = new ArrayList<>();
// 用累加器篩選元素
for(Dish d: menu){
    if(d.getCalories() < 400){
        lowCaloricDishes.add(d);
    }
}
// 用匿名類對菜餚排序
Collections.sort(lowCaloricDishes, new Comparator<Dish>() {
    public int compare(Dish d1, Dish d2){
        return Integer.compare(d1.getCalories(), d2.getCalories());
    }
});
// 處理排序後的菜名列表
List<String> lowCaloricDishesName = new ArrayList<>();
for(Dish d: lowCaloricDishes){
    lowCaloricDishesName.add(d.getName());
}
Java8版本:
import static java.util.Comparator.comparing;
import static java.util.stream.Collectors.toList;
List<String> lowCaloricDishesName = menu.stream()
                                        .filter(d -> d.getCalories() < 400)    // 選出400卡路里如下的菜餚
                                        .sorted(comparing(Dish::getCalories))    // 按照卡路里排序
                                        .map(Dish::getName)                    // 提取菜餚名稱
                                        .collect(toList());                    // 將全部的名稱保存在List中
利用多核架構並行執行,只須要把stream()換成parallelStream()複製代碼

Java 8中的Stream API特性:數據庫

  • 聲明性——更簡潔,更易讀
  • 可複合——更靈活
  • 可並行——性能更好

流定義:編程

  • 元素序列——就像集合同樣,流也提供了一個接口,能夠訪問特定元素類型的一組有序 值。
  • 源——流會使用一個提供數據的源,如集合、數組或輸入/輸出資源。 請注意,從有序集 合生成流時會保留原有的順序。由列表生成的流,其元素順序與列表一致。
  • 數據處理操做——流的數據處理功能支持相似於數據庫的操做,以及函數式編程語言中的經常使用操做,如filter、map、reduce、find、match、sort等。流操做能夠順序執行,也可並行執行。
  • 流水線——不少流操做自己會返回一個流,這樣多個操做就能夠連接起來,造成一個大的流水線。這讓咱們下一章中的一些優化成爲可能,如延遲和短路。流水線的操做能夠看做對數據源進行數據庫式查詢。
  • 內部迭代——與使用迭代器顯式迭代的集合不一樣,流的迭代操做是在背後進行的。

2. 流與集合

集合與流之間的差別就在於何時進行計算。集合是一個內存中的數據結構,它包含數據結構中目前全部的值——集合中的每一個元素都得先算出來才能添加到集合中。相比之下,流則是在概念上固定的數據結構(你不能添加或刪除元素),其元素則是按需計算的。集合和流的另外一個關鍵區別在於它們遍歷數據的方式。數組

2.1 只能遍歷一次

和迭代器相似,流只能遍歷一次。遍歷完以後,咱們就說這個流已經被消費掉了。如下代碼會拋出一個異常,說流已被消費掉了:數據結構

List<String> title = Arrays.asList(「Java8」,」In」, 「Action」);
Stream<String> s = title.stream();
s.forEach(System.out::println);
s.forEach(System.out::println);

Exception in thread "main" java.lang.IllegalStateException: stream has already been operated upon or closed
    at java.util.stream.AbstractPipeline.sourceStageSpliterator(AbstractPipeline.java:279)
    at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:580)
    at com.lujiahao.learnjava8.chapter4.StreamAndCollection.main(StreamAndCollection.java:16)複製代碼

2.2 外部迭代與內部迭代

使用Collection接口須要用戶去作迭代(好比用for-each),這稱爲外部迭代。相反,Streams庫使用內部迭代架構

集合:用for-each循環外部迭代
List<String> names = new ArrayList<>();
for(Dish d: menu){
    names.add(d.getName());
}

集合:用背後的迭代器作外部迭代
List<String> names = new ArrayList<>();
Iterator<String> iterator = menu.iterator();
while(iterator.hasNext()) {
    Dish d = iterator.next();
    names.add(d.getName());
}

流:內部迭代
List<String> names = menu.stream()
                        .map(Dish::getName)
                        .collect(toList());複製代碼

3. 流操做

java.util.stream.Stream中的Stream接口定義了許多操做。它們能夠分爲兩大類。能夠鏈接起來的流操做稱爲中間操做,關閉流的操做稱爲終端操做。中間操做:除非流水線上觸發一個終端操做,不然中間操做不會執行任何處理。終端操做:會從流的流水線生成結果。其結果是任何不是流的值。編程語言

流的使用通常包括三件事:函數式編程

  • 一個數據源(如集合)來執行一個查詢;
  • 一箇中間操做鏈,造成一條流的流水線;
  • 一個終端操做,執行流水線,並能生成結果。

流的流水線背後的理念相似於構建器模式。函數

常見流操做:性能

4. 小結

如下是你應從本章中學到的一些關鍵概念。

  • 流是「從支持數據處理操做的源生成的一系列元素」。
  • 流利用內部迭代:迭代經過filter、map、sorted等操做被抽象掉了。
  • 流操做有兩類:中間操做和終端操做。
  • filter和map等中間操做會返回一個流,並能夠連接在一塊兒。能夠用它們來設置一條流水線,但並不會生成任何結果
  • forEach和count等終端操做會返回一個非流的值,並處理流水線以返回結果。
  • 流中的元素是按需計算的。

資源獲取

  • 公衆號回覆 : Java8 便可獲取《Java 8 in Action》中英文版!

Tips

  • 歡迎收藏和轉發,感謝你的支持!(๑•̀ㅂ•́)و✧
  • 歡迎關注個人公衆號:莊裏程序猿,讀書筆記教程資源第一時間得到!
相關文章
相關標籤/搜索