Java8新特性之:流(一)

一. 流的概念java

    流是Java API的新成員,它容許你以聲明性的方式處理數據集合(經過查詢語句來表達,而不是臨時編寫一個實現)。數據結構

    Stream API的特性:app

        -- 聲明性:更簡潔,更易讀;ide

        -- 可複合:更靈活;性能

        -- 可並行:性能更好。優化


    1.流的定義從支持數據處理操做生成的元素序列this

        流有兩個重要特色:spa

            -- 流水線:不少流操做自己會返回一個流,這樣多個操做就能夠連接起來,造成一個大的流水線;接口

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

        案例:

public class Dish {
    private final String name;
    private final int calories;
    private final boolean vegetarian;
    private final DishType type;
    
    public Dish(String name, boolean vegetarian, int calories, DishType type) {
        this.name = name;
        this.vegetarian = vegetarian;
        this.calories = calories;
        this.type = type;
    }
    
    public String getName() {
        return name;
    }
    
    public int getCalories() {
        return calories;
    }
    
    public boolean isVegetarian() {
        return vegetarian;
    }
}
public static void main(String[] args) {
    List<Dish> menu = Arrays.asList(
        new Dish("pork", false, 800, DishType.MEAT),
        new Dish("prawns", false, 300, DishType.FISH),
        new Dish("chicken", false, 700, DishType.MEAT),
        new Dish("rice", true, 350, DishType.OTHER)
    );
    
    List<String> threeHighCaloricDishNames = menu.stream() //菜單流Stream<Dish>
        .filter(d -> d.getCalories() > 300) //Stream<Dish>
        .map(Dish::getName) //Stream<String>
        .limit(3) //Stream<String>
        .collect(toList()); //List<String>,collect操做開始處理流水線
        
    System.out.println(threeHighCaloricDishNames);  //結果:[pork, chicken, rice]
}

        數據源:menu,它給流提供一個元素序列,而後對流應用一系列數據處理操做:filter、map、limit和collect。除了collect以外,全部這些操做都會返回一個流,這樣它們就能夠接成一條流水線,因而就能夠當作對源的一個查詢。最後collect開始處理流水線,並返回結果。在調用collect以前,沒有任何結果產生,實際上根本沒有從menu裏選擇元素。能夠理解爲:鏈中的方法都在排隊等待,直到調用collect。


    2.流操做

        流操做分爲中間操做和終端操做。能夠鏈接起來的流操做稱爲中間操做,關閉流的操做稱爲終端操做。

        中間操做:中間操做會返回另外一個流。這讓多個操做能夠鏈接起來造成一個查詢。

                        除非流水線上觸發一個終端操做,不然中間操做不會執行任何處理。這是由於中間操做通常均可以合併起來,在終端操做時一次性所有處理。

        終端操做:終端操做會從流的流水線生成結果。其結果是任何不是流的值。

public static void main(String[] args) {
    List<Dish> menu = Arrays.asList(
    new Dish("pork", false, 800, DishType.MEAT),
    new Dish("prawns", false, 300, DishType.FISH),
    new Dish("chicken", false, 700, DishType.MEAT),
    new Dish("rice", true, 350, DishType.OTHER)
    );
    
    List<String> names = menu.stream()
        .filter(d -> {
            System.out.println("filtering " + d.getName());
            return d.getCalories() > 130;
        })
        .map(d -> {
            System.out.println("mapping " + d.getName());
            return d.getName();
        })
        .limit(3)
        .collect(toList());
        
    System.out.println(names);
}

輸出結果:
filtering pork
mapping pork
filtering prawns
mapping prawns
filtering chicken
mapping chicken
[pork, prawns, chicken]

        根據上例能夠發現,儘管filter和map是兩個獨立的操做,但它們合併到同一次遍歷中了(這種技術稱爲循環合併)。


二. 流與集合的異同

    集合與流之間的差別在於何時進行計算。

    集合:是一個內存中的數據結構,它包含數據結構中目前全部的值--集合中的每一個元素都得先算出來才能添加到集合中。

    流:是在概念上固定的數據結構(不能添加或刪除元素),其元素師按需計算的。

    流就像是一個延遲建立的集合:只有在消費者要求的時候纔會計算值。


    1.流只能遍歷一次

        流和迭代器相似,只能遍歷一次,遍歷後說明這個流已經被消費了。

public static void main(String[] args) {
    List<String> title = Arrays.asList("dispatch", "settlement", "wyvern");
    Stream<String> s = title.stream();
    s.forEach(System.out::println);
    s.forEach(System.out::println); //當執行到這裏時會報IllegalStateException: stream has already been operated upon or closed
}


    2.集合和流在遍歷數據方式的區別

        Collection接口須要作迭代(for-each),稱爲外部迭代。

        Stream庫使用內部迭代。

        內部迭代的優勢:項目能夠透明地並行處理,或者用更優化的順序進行處理。

        內部迭代的前提:你已經預先定義好了可以隱藏迭代的操做列表,例如filter或map。

相關文章
相關標籤/搜索