1. 程式人生 > >JDK8的集合流式的簡易操作

JDK8的集合流式的簡易操作

需要Lambda表示式的原因主要有三個:

1. 更緊湊的程式碼

2. 通過提供額外的功能對方法的功能進行修改的能力

3. 更好地支援多核處理

更緊湊的程式碼

Lambda表示式以一種簡潔的方式去實現僅有一個方法的Java類。

例如,如果程式碼中有大量的匿名內部類–諸如用於UI應用中的監聽器與處理器實現,以及用於併發應用中的Callable與Runnable實現–在使用了Lambda表示式之後,將使程式碼變得非常短,且更易於理解。

修改方法的能力

有時,方法不具備我們想要的一些功能。例如,Collection介面中的contains()方法只有當傳入的物件確實存在於該集合物件中時才會返回true。但我們無法去幹預該方法的功能,比如,若使用不同的大小寫方案也可以認為正在查詢的字串存在於這個集合物件中,我們希望此時contains()方法也能返回true。

簡單點兒說,我們所期望做的就是”將我們自己的新程式碼傳入”已有的方法中,然後再呼叫這個傳進去的程式碼。Lambda表示式提供了一種很好的途徑來代表這種被傳入已有方法且應該還會被回撥的程式碼。

更好地支援多核處理

當今的CPU具備多個核心。這就意味著,多執行緒程式能夠真正地被並行執行,這完全不同於在單核CPU中使用時間共享這種方式。通過在Java中支援函數語言程式設計語法,Lambda表示式能幫助你編寫簡單的程式碼去高效地應用這些CPU核心。

例如,你能夠並行地操控大集合物件,通過利用並行程式設計模式,如過濾、對映和化簡(後面將會很快接觸到這些模式),就可使用到CPU中所有可用的硬體執行緒。

一. 基本概念
1.1 為什麼加入 集合的流式操作     
        JDK8 的Stream 是一個受到 函數語言程式設計 和 多核時代影響而產生的東西。很多時候我們需要到底層返回資料,上層再對資料進行遍歷,進行一些資料統計,但是之前的Java API 中很少有這種方法,這就需要我們自己來 Iterator 來遍歷,如果JDK 能夠為我們提供一些這種方法,並且能夠為我們優化就好了。
         所以JDK8加入 了 java.util.stream包,實現了集合的流式操作,流式操作包括集合的過濾,排序,對映等功能。根據流的操作性,又可以分為 序列流 和 並行流。根據操作返回的結果不同,流式操作又分為中間操作和最終操作。大大方便了我們對於集合的操作。
最終操作:返回一特定型別的結果。
中間操作:返回流本身。
1.2 什麼是 流
        Stream 不是 集合元素,也不是資料結構,它相當於一個 高階版本的 Iterator,不可以重複遍歷裡面的資料,像水一樣,流過了就一去不復返。它和普通的 Iterator 不同的是,它可以並行遍歷,普通的 Iterator 只能是序列,在一個執行緒中執行。

二. 序列流和並行流:
        序列流操作在一個執行緒中依次完成。並行流在多個執行緒中完成,主要利用了 JDK7 的 Fork/Join 框架來拆分任務和加速處理。相比序列流,並行流可以很大程度提高程式的效率。

三. 中間操作 和 最終操作        
中間操作:
filter(): 對元素進行過濾
sorted():對元素排序
map():元素對映
distinct():去除重複的元素
最終操作:
forEach():遍歷每個元素。
reduce():把Stream 元素組合起來。例如,字串拼接,數值的 sum,min,max ,average 都是特殊的 reduce。
collect():返回一個新的集合。
min():找到最小值。
max():找到最大值。

3.1 filter() 對元素進行過濾
Demo(有一連結串列,{1,2,3,4,5},把偶數過濾掉):

public class Test {  
    public static void main(String[] args) throws InterruptedException {  
        List list = new ArrayList();  
        for(int i = 1 ; i <= 5; ++i){  
            list.add(i);  
        }  
        list.stream().filter(param -> (int)param % 2 == 1)  
                    .forEach(System.out::println);  
    }  
}  


輸出:

1  
3  
5  

3.2 sorted() 對元素進行排序
Demo(有一連結串列,{2,3,1,5,4},從小到大排序):

public class Test {  
    public static void main(String[] args) throws InterruptedException {  
        List list = new ArrayList();  
        list.add(2);  
        list.add(3);  
        list.add(1);  
        list.add(5);  
        list.add(4);  
        list.stream().sorted().forEach(System.out::println);  
    }  
}  


輸出:

1  
2  
3  
4  
5  



Ps1: 此時為升序,那麼有時候我們可能會需要到降序,此時做法可以如下:
        流除了提供預設的升序 sorted() 方法,也提供了:    

Stream<T> sorted(Comparator<? super T> comparator);  

那麼,自定義比較函式即可,如下程式碼:

public class Test {  
    public static void main(String[] args) throws InterruptedException {  
        List list = new ArrayList();  
        list.add(2);  
        list.add(3);  
        list.add(1);  
        list.add(5);  
        list.add(4);  
//      list.stream().sorted().forEach(System.out::println);  
        list.stream().sorted( (param1,param2) -> ((int)param1 < (int)param2 ? 1 : -1 ) )  
                .forEach(System.out::println);  
    }  
}  


輸出為:

5  
4  
3  
2  
1  


3.3 map() 元素對映
        也就是說,原來的連結串列的每個元素可以按照規則變成相應的元素。
Demo(連結串列 (1,0),變成 true,false):

public class Test {  
    public static void main(String[] args) throws InterruptedException {  
        List list = new ArrayList();  
        list.add(1);  
        list.add(0);  
        list.stream().map( param -> (int)param == 1 ? true:false )  
                .forEach(System.out::println);  
    }  
}  


輸出:

true  
false  


3.4  distinct() 去除重複元素
Demo:

public class Test {  
    public static void main(String[] args) throws InterruptedException {  
        List list = new ArrayList();  
        list.add(1);  
        list.add(1);  
        list.add(0);  
        list.stream().distinct().forEach(System.out::println);  
    }  
}  


3.5 reduce() :把Stream 元素組合起來。
Demo(從1加到5):

public class Test {  
    public static void main(String[] args) throws InterruptedException {  
        List list = new ArrayList();  
        list.add(1);  
        list.add(2);  
        list.add(3);  
        list.add(4);  
        list.add(5);  
        System.out.println(  
                list.stream().reduce((param1,param2) ->(int)param1 + (int)param2 ).get());  
    }  
}  

注意,reduce() 返回一個 Optional 型別的物件,可以通過 get() 方法獲得值。

3.6 collect() :返回一個新的集合
Demo(先把 list 集合的 奇數去掉,然後把剩下的偶數返回到 _list 集合中):

public class Test {  
    public static void main(String[] args) throws InterruptedException {  
        List list = new ArrayList();  
        list.add(1);  
        list.add(2);  
        list.add(3);  
        list.add(4);  
        list.add(5);  
          
        List _list = (List) list.stream().filter((param) -> (int)param % 2 == 0)  
                        .collect(Collectors.toList());  
        _list.forEach(System.out::println);  
    }  
}  


輸出:

2  
4  


3.7 min(),max()  找到最大值最小值

public class Test {  
    public static void main(String[] args) throws InterruptedException {  
        List list = new ArrayList();  
        list.add(1);  
        list.add(2);  
        list.add(3);  
        list.add(4);  
        list.add(5);  
          
        System.out.println(list.stream().min(  
                (param1,param2) -> (int)param1 > (int)param2 ? 1:-1 ).get());  
        System.out.println(list.stream().max(  
                (param1,param2) -> (int)param1 > (int)param2 ? 1:-1 ).get());  
    }  
}  


        注意, min(),max() 方法也是返回 Optional 物件, 可以通過 get() 方法返回值。
        
總結:
1. 流式操作的引入:提高執行效率(並行),方便編碼(有很多API 可用),提高可讀性。
2. 流的分類:可以分為序列流和並行流;對於操作:可以分為中間操作和最終操作
3. 流API:
        中間操作:
                filter(): 對元素進行過濾;
                sorted():對元素排序;
                map():元素對映;
                distinct():去除重複的元素 。
        最終操作:
                forEach():遍歷每個元素;
                reduce():把Stream 元素組合起來。例如,字串拼接,數值的 sum,min,max ,average 都是特殊的 reduce。
                collect():返回一個新的集合。
                min():找到最小值。
                max():找到最大值。