java 8 系列之 03 流介紹

主要內容

本篇主要是初步瞭解一下Stream是什麼,有哪些種類,初步接觸一下。

  1. 流是什麼
  2. 流與集合
  3. 流操作種類

流是什麼

流簡介

流(Stream)是Java API的新成員,它允許你以聲明性方式處理數據集合(通過查詢語句來表達,而不是臨時編寫一個,有點像sql語句已經定義好了一部分可以使用函數,然後組合使用即可)。此外還可以透明地並行處理。

流簡短的定義:從支持數據處理操作的源生成的元素序列。

  1. 元素序列——就像集合一樣,流也提供了一個接口,可以訪問特定元素類型的一組有序值。因爲集合是數據結構,所以它的主要目的是以特定的時間/空間複雜度存儲和訪問元素(如ArrayList 與 LinkedList)。但流的目的在於表達計算,比如你前面見到的filter、sorted和map。集合講的是數據,流講的是計算。
  2. 源 ——流會使用一個提供數據的源,入集合、數組和輸入輸出源。注意的是,從有序集合生成流時會保留原有的順序。由列表生成的流,其元素順序和列表一致。
  3. 數據處理操作——流的數據處理功能支持類似於數據庫的操作,以及函數式編程語言中的常用操作,入filter、map、reduce、find、match、sort等。流可以順序處理也可以並行執行。
  4. 流水線——很多流操作本身會返回一個流,這樣多個操作就可以鏈接起來,行程一個大的流水線。
  5. 內部迭代——與使用迭代器顯示迭代的集合不同,流的迭代是在別後進行的。

下面看一個簡單的例子:

//未使用流處理數據
List< Dish > lowCaloricDishes = new ArrayList< >();
//用匿名類對 菜餚排序
for(Dish d: menu){
  Collections.sort(lowCaloricDishes, new Comparator< Dish >() { 
     public int compare(Dish d1, Dish d2){
        return Integer.compare(d1.getCalories(), d2.getCalories());
      }
};


//使用Stream流來處理
List< String > lowCaloricDishesName =
               menu.stream()     //產生流
               .filter(d -> d.getCalories() < 400)  //選出400卡路里一下的菜餚
                .sorted(comparing(Dish::getCalories)) //按照卡路里進行排序
                .map(Dish::getName)    //得到菜的名字
                .collect(toList());    //將所有的名稱保存在List中

上面就是一個我們經常在開發中使用到的代碼,現在我們來看一下上面代碼的好處:

  1. 代碼以聲明性方式寫的:說明想要完成什麼,而不是說明如何實現一個操作。是代碼簡潔易讀
  2. 可以把幾個基礎操作鏈接起來,來表達複雜的數據處理。

由此可以總結出 Java 8 中的Stream API可以讓你寫出這樣的代碼:

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

流與集合

Java現有的集合概念和新的流概念都提供了接口,來配合代表元素型有序值的數據接口。所謂有序,就是說我們一般是按順序取用值,而不是隨機取用的。那這兩者有什麼區別呢?

我們先來打個直觀的比方吧。比如說存在DVD裏的電影,這就是一個集合(也許是字節,也許是幀,這個無所謂),因爲它包含了整個數據結構。現在再來想想在互聯網上通過視頻流看同樣的電影。現在這是一個流(字節流或幀流)。流媒體視頻播放器只要提前下載用戶觀看位置的那幾幀就可以了,這樣不用等到流中大部分值計算出來,你就可以顯示流的開始部分了(想想觀看直播足球賽)。特別要注意,視頻播放器可能沒有將整個流作爲集合,保存所需要的內存緩衝區——而且要是非得等到最後一幀出現才能開始看,那等待的時間就太長了。出於實現的考慮,你也可以讓視頻播放器把流的一部分緩存在集合裏,但和概念上的差異不是一回事。

粗略地說,集合與流之間的差異就在於什麼時候進行計算。集合是一個內存中的數據結構,它包含數據結構中目前所有的值——集合中的每個元素都得先算出來才能添加到集合中。(你可以往集合里加東西或者刪東西,但是不管什麼時候,集合中的每個元素都是放在內存裏的,元素都得先算出來才能成爲集合的一部分。)相比之下,流則是在概念上固定的數據結構(你不能添加或刪除元素),其元素則是按需計算的。 這對編程有很大的好處。這個思想就是用戶僅僅從流中提取需要的值,而這些值——在用戶看不見的地方——只會按需生成。這是一種生產者-消費者的關係。從另一個角度來說,流就像是一個延遲創建的集合:只有在消費者要求的時候纔會計算值(用管理學的話說這就是需求驅動,甚至是實時製造)。

與此相反,集合則是急切創建的(供應商驅動:先把倉庫裝滿,再開始賣,就像那些曇花一現的聖誕新玩意兒一樣)。以質數爲例,要是想創建一個包含所有質數的集合,那這個程序算起來就沒完沒了了,因爲總有新的質數要算,然後把它加到集合裏面。當然這個集合是永遠也創建不完的,消費者這輩子都見不着了。

下圖就是用DVD對比在線流媒體的例子展示了流和集合之間的差異。

這裏寫圖片描述

另一個例子是用瀏覽器進行互聯網搜索。假設你搜索的短語在Google或是網店裏面有很多匹
配項。你用不着等到所有結果和照片的集合下載完,而是得到一個流,裏面有最好的10個或20 3
個匹配項,還有一個按鈕來查看下面10個或20個。當你作爲消費者點擊“下面10個”的時候,供
應商就按需計算這些結果,然後再送回你的瀏覽器上顯示。

集合與流的區別

  1. 流只能遍歷一次,遍歷完之後就說這個流已經被消費掉了。這與集合不同,集合可以多次使用。
  2. 流是內部迭代,集合是外部迭代。也就是集合需要自己寫代碼利用Iterator來進行遍歷,而流是已經幫我們寫好了迭代代碼,我們只要用就可以。

流操作種類

流操作有倆類操作

  1. 中間操作:諸如filter或sorted操作會返回一個流。而這類操作定義的時候不會立即執行,而是等到遇見終端操作纔會執行。
  2. 終端操作:從流的流水線生成結果。其結果是任何不是流的值,比如List,Integer。
發佈了39 篇原創文章 · 獲贊 11 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章