1. 程式人生 > >Java8之Stream(1)

Java8之Stream(1)

Java8出來有一年多的時間了,在最開始出來的時候,我只是簡單的看了一下他的文件,並且看了一下其中的一些例子,並沒有將自己的日常開發切換到Java8中,最近的專案開發中,公司要求將JDK的平臺升級到Java8中,因此我覺得有必要逐漸梳理一下Java8中的一些新的特性,Java8其實在Java的發展過程中絕對是里程碑式的存在,有很多很多新穎的程式設計方式,可以這麼說吧,Lambda的出現改變了Java的程式設計方式,使這門語法緊湊的純純面向物件的語言,開始相容函數語言程式設計的風格,我不想評價是不是進步(因為面向函式的語言其實已經很多了,並且很流行),但是最起碼Java平臺做出來改變,我更想說是一種演進和演變。

我們來一起學習一下Java8的新特性Stream,其中可能需要你具備一些Lambda的知識,一些Collections的知識,然後我們就快速上手吧,其中為了說明平行計算,我可能會介紹一下JDK7中的Fork Join和快速排序演算法等。

一、Stream簡單介紹

Stream是Java8中比較閃亮的一個新特性,但是它絕對不等同於IO包中的Stream和解析XML的Stream,JAVA  8中的Stream也不是一個容器,它絕對不是用來儲存資料的,他是對JDK中Collections的一個增強,他只專注於對集合物件的便利,高效的聚合操作,它不僅支援序列的操作功能,而且還藉助JDK1.7 中的Fork-Join機制支援了並行模式,你無需編寫任何一行並行相關的程式碼,就能高效方便的寫出高併發的程式,尤其在現在多核CPU的時代,最大程度的利用CPU的超快計算能力顯得尤為重要。

二、Stream之Hello World

在開始介紹Stream的各個使用細節的時候,我們先來快速看一個入門的示例,先有一個簡單的認識,為了能夠體現出來Stream的便捷,我們同樣的需求,分別使用傳統的方式和Stream的方式各實現一次。

2.1 需求描述

在一個水果的集合中,獲取蘋果這一個單品並且以價格降序的方式形成一個新的集合,這個新的集合中只存放價格,也就是List<Integer>,雖然這個例子在實際中有些扯淡,但是我們為了簡單演示一下如何使用Stream,所以重點關注用法,不用理會需求的嚴謹與否。

2.2 程式碼實現

Fruit類,程式碼如下:

package com.wangwenjun.stream;

/**

 * Created by wangwenjun on 2015/8/8.

 */

public class Fruit {

    private final String name;

    private final double price;

    public Fruit(String name, double price) {

        this.name = name;

        this.price = price;

    }

    public String getName() {

        return name;

    }

    public double getPrice() {

        return price;

    }

}

FruitSelector類,程式碼如下

package com.wangwenjun.stream;

import java.util.ArrayList;

import java.util.List;

/**

 * Created by wangwenjun on 2015/8/8.

 */

public abstract class FruitSelector {

    protected final static String CANDIDATE_FRUIT = "apple";

    private List<Fruit> getData(){

        final List<Fruit> data = new ArrayList<Fruit>(){

            {

                add(new Fruit("apple",22.1));

                add(new Fruit("apple",22.2));

                add(new Fruit("apple",22.3));

                add(new Fruit("apple",22.4));

                add(new Fruit("apple",22.5));

                add(new Fruit("apple",22.6));

                add(new Fruit("apple",22.7));

                add(new Fruit("orange",22.8));

                add(new Fruit("orange",22.9));

                add(new Fruit("orange",23.0));

                add(new Fruit("orange",23.1));

                add(new Fruit("orange",24.2));

                add(new Fruit("orange",22.3));

                add(new Fruit("banana",22.4));

                add(new Fruit("banana",22.2));

                add(new Fruit("banana",22.2));

                add(new Fruit("banana",22.2));

                add(new Fruit("banana",22.2));

            }

        };

        return data;

    }

    public List<Double> select()

    {

        List<Fruit> fruits= getData();

        return doFilter(fruits);

    }

    protected abstract List<Double> doFilter(final List<Fruit> fruits);

}

IteratorFruitSelector類程式碼如下,他是使用我們傳統迭代的方式去做這樣的工作。

package com.wangwenjun.stream;

import java.util.*;

public class IteratorFruitSelector extends FruitSelector {

    @Override

    protected List<Double> doFilter(List<Fruit> fruits) {

        //get the fruit name is 'apple'

        List<Fruit> appleList = new ArrayList<>();

        Iterator<Fruit> iterator = fruits.iterator();

        for (; iterator.hasNext(); ) {

            Fruit fruit = iterator.next();

            if (fruit.getName().equals(CANDIDATE_FRUIT)) {

                appleList.add(fruit);

            }

        }

        //do sort.

        Collections.sort(appleList, (o1, o2) -> {

            if (o1.getPrice() > o2.getPrice()) return 1;

            else if (o1.getPrice() == o2.getPrice()) return 0;

            else return -1;

        });

        //do filter.

        List<Double> applePriceList = new ArrayList<>();

        for (Fruit fruit : appleList) {

            applePriceList.add(fruit.getPrice());

        }

        return applePriceList;

    }

}

我們使用Stream的方式看看,程式碼如何去寫呢?

package com.wangwenjun.stream;

import java.util.Comparator;

import java.util.List;

import static java.util.stream.Collectors.toList;

/**

 * Created by wangwenjun on 2015/8/8.

 */

public class StreamFruitSelector extends FruitSelector {

    @Override

    protected List<Double> doFilter(List<Fruit> fruits) {

        return fruits.stream().filter(f -> f.getName().equals(CANDIDATE_FRUIT))

                .sorted(Comparator.comparing(Fruit::getPrice))

                .map(Fruit::getPrice)

                .collect(toList());

    }

}

程式碼寫完了,簡單對照一下,你是不是能看出來,採用Stream的方式比傳統的方式要簡潔很多很多,程式碼量至少少了2/3.

2.3 簡單測試

好了,我們寫一下單元測試,看看是不是兩者執行情況一樣呢?當然我們並沒有測試效能的意思,如果你想測試效能,可以把資料量改到很大,並且Stream採用並行的工作模式,差異還是蠻多的。

package com.wangwenjun.stream;

import org.junit.Test;

import java.util.List;

/**

 * Created by wangwenjun on 2015/8/8.

 */

public class FruitSelectorTest

{

    @Test

    public void testIterator()

    {

        FruitSelector selector = new IteratorFruitSelector();

        List<Double> result = selector.select();

        System.out.println(result);

    }

    @Test

    public void testStream()

    {

        FruitSelector selector = new StreamFruitSelector();

        List<Double> result = selector.select();

        System.out.println(result);

    }

}

執行結果不言而喻了吧

[22.1, 22.2, 22.3, 22.4, 22.5, 22.6, 22.7]

[22.1, 22.2, 22.3, 22.4, 22.5, 22.6, 22.7]


完整文件下載地址在:http://download.csdn.net/detail/wangwenjun69/8981633