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