Java8特性②Stream簡介

流是什麼

是Java API的新成員,它容許你以聲明性方式處理數據集合(經過查詢語句來表達,而不是臨時編寫一個實現)。能夠把它們當作遍歷數據集的高級迭代器。此外流還能夠透明地並行處理,無需寫任何多線程代碼了。以下面代碼所示:java

public static List<String> getLowCalorisInJava8(List<Dish> dishes) {

    List<String> lowColorisDish = dishes.stream() //parallelStream() 並行流
                .filter((Dish d) -> d.getCalories() < 400) //篩選
                .sorted(Comparator.comparing(Dish::getCalories)) //排序
                .map(Dish::getName) //提取名稱
                .collect(Collectors.toList()); //將全部名稱存入List中

    return lowColorisDish;
}

Dish類數據庫

package com.company.bean;

import java.util.Arrays;
import java.util.List;

/**
 * Created by liuguoquan on 2017/4/26.
 */
public class Dish {

    private String name;
    private boolean vegetarian;
    private int calories;
    private Type type;

    public enum Type { MEAT, FISH, OTHER }

    public Dish(String name, boolean vegetarian, int calories, Type type) {
        this.name = name;
        this.vegetarian = vegetarian;
        this.calories = calories;
        this.type = type;
    }

    public String getName() {
        return name;
    }

    public boolean isVegetarian() {
        return vegetarian;
    }

    public int getCalories() {
        return calories;
    }

    public Type getType() {
        return type;
    }

    @Override
    public String toString() {
        return name;
    }

    public static final List<Dish> menu =
            Arrays.asList( new Dish("pork", false, 800, Dish.Type.MEAT),
                    new Dish("beef", false, 700, Dish.Type.MEAT),
                    new Dish("chicken", false, 400, Dish.Type.MEAT),
                    new Dish("french fries", true, 530, Dish.Type.OTHER),
                    new Dish("rice", true, 350, Dish.Type.OTHER),
                    new Dish("season fruit", true, 120, Dish.Type.OTHER),
                    new Dish("pizza", true, 550, Dish.Type.OTHER),
                    new Dish("prawns", false, 400, Dish.Type.FISH),
                    new Dish("salmon", false, 450, Dish.Type.FISH));
}

流簡介

流就是從支持數據處理操做的源生成的元素序列。編程

  • 元素序列:流也提供了一個接口,能夠訪問特定元素類型的一組有序 值。由於集合是數據結構,因此它的主要目的是以特定的時間/空間複雜度存儲和訪問元 素(如 ArrayList 與 LinkedList )。但流的目的在於表達計算, 好比你前面見到的 filter、sorted和map。集合講的是數據,流講的是計算。數組

  • 源:流會使用一個提供數據的源,如集合、數組或輸入/輸出資源。 請注意,從有序集 合生成流時會保留原有的順序。由列表生成的流,其元素順序與列表一致。數據結構

  • 數據處理操做:流的數據處理功能支持相似於數據庫的操做,以及函數式編程語言中 的經常使用操做,如filter、map、reduce、find、match、sort等。流操做能夠順序執 行,也可並行執行。多線程

流操做的兩個重要的特色:編程語言

  • 流水線:不少流操做自己會返回一個流,這樣多個操做就能夠連接起來,造成一個大的流水線。流水線的操做能夠 看做對數據源進行數據庫式查詢。ide

  • 內部迭代:與使用迭代器顯式迭代的集合不一樣,流的迭代操做是在背後進行的。函數式編程

流與集合

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

流只能遍歷一次。遍歷完以後,這個流已經被消費掉了。能夠從原始數據源那裏再得到一個新的流來從新遍歷一遍。

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:流已被操做

Collection接口須要用戶去作迭代(好比用for-each),這稱爲外部迭代。Streams庫使用內部迭代——它幫你把迭代作了,還把獲得的流值存在了某個地方,你只要給出一個函數說要幹什麼就能夠了。Streams庫的內部迭代能夠自動選擇一種適 合你硬件的數據表示和並行實現。與此相反,一旦經過寫for-each而選擇了外部迭代,那你基 本上就要本身管理全部的並行問題了。

流操做

java.util.stream.Stream 中的 Stream 接口定義了許多操做。它們能夠分爲兩大類。

  • 中間操做:filter、map、limit等能夠連成一條流水線的操做;

  • 終端操做:collect等觸發流水線執行並關閉流的操做;

中間操做

諸如filter或sorted等中間操做會返回另外一個流。這讓多個操做能夠鏈接起來造成一個查 詢。重要的是,除非流水線上觸發一個終端操做,不然中間操做不會執行任何處理,這是由於中間操做通常均可以合併起來,在終端操做時一次性所有處理。儘管filter和map是兩個獨立的操做,但它們合併到同一次遍歷中了(咱們把這種技術叫做循環 合併)。

終端操做

終端操做會從流的流水線生成結果。其結果是任何不是流的值,好比List、Integer,甚至void。

使用流

流的使用通常包括三件事:

  • 一個數據源(如集合)來執行一個查詢;

  • 一箇中間操做鏈,造成一條流的流水線;

  • 一個終端操做,執行流水線,並能生成結果;

流的流水線背後的理念相似於構建器模式。在構建器模式中有一個調用鏈用來設置一套配 置(對流來講這就是一箇中間操做鏈),接着是調用built方法(對流來講就是終端操做)。

參考資料

《Java 8 實戰》

相關文章
相關標籤/搜索