Java 8 - 利用Lambda與Stream來改寫Collection的基本操作

本篇將說明利用Java 8內的新工具Stream interface來改寫一般操作collection的使用,如:針

對ArrayList,本來要透過走訪iterator來做判斷的塞選,但現在可以透過Stream下的

filter method輕鬆做到,利用Java 8新支援的Lambda表示式使得語法將更簡潔及提高效能!

首先,在這邊不會提到Lambda表示式的語法介紹,如果有問題可以至良葛格的網站瀏覽囉!

目前Java 8的ArrayList有實作java.util.collection,其下有定義一stream method,因此可以取得

一 java.util.Stream的reference,而Stream type到底可以作什麼事?

一般我們走訪一個List,可能會先取得他的iterator,再利用迴圈來判斷hasNext()及next()

來取得對應的reference,如此一來就可以進行該reference的操作,在這邊我們稱為外部

的iterator

而取得了stream reference之後,我們就不需要再做iterator的迴圈操作,可以做的事情stream

內的method有定義,如filter,可以取得一過濾掉stream所存放的物件後的stream

reference,而不符合filter條件的stream所存放的物件就會被遺棄!! 在這邊可以想像為內部的

iterator操作囉!!

PS. 這邊的Stream 為 java.util.Stream,個人覺得相當於內部迭代的資源控制器! 以此介面

可以做相關操作,如filter、collect、map等操作。

1. filter的使用

相關程式碼如下:
List<Transcript> studentList = new ArrayList<Transcript>();
Transcript t1 = new Transcript("Ben", 87, 91, 80);
Transcript t2 = new Transcript("Sjkok", 94, 99, 65);
Transcript t3 = new Transcript("Aaron", 44, 55, 100);
Transcript t4 = new Transcript("Zhibin", 77, 88, 66);
studentList.add(t1);
studentList.add(t2);
studentList.add(t3);
studentList.add(t4);

//Use filter and count method
long mathPassCount = studentList.stream()
                                .filter(trans -> trans.getMath() > 60)
                                .count();
System.out.println(mathPassCount);

Transcript的定義請見Java - Class fields sort by Collections Class and Comparator interface

首先,在這邊定義了一Transcript類別的List集合項目

緊接著,我們要完成的功能為,取得哪一位同學其數學的成績是有及格的!

先取得該list的stream reference,緊接著利用filter method帶入參數的語法為一不具名的函式

trans -> trans.getMath() > 60

-> 區隔了參數與Lambda表示式

trans為帶入的參數;trans.getMath() > 60為Lambda表示式內文

trans的型態為Transcript,可以寫成Transcript trans或省略

PS. Lambda會由studentList的型別去自動判定喔

而stream reference再呼叫count method來得知目前Stream中有多少Transcript型別的物件

2. collect的使用

collect能夠搭配過濾來取得當下Transcript物件喔,看您要回傳Set or List的形式

如我要取得國文分數低於60分以下的同學,並列出其名字!

相關程式碼如下:
List<Transcript> chineseNoPass = studentList.stream()
                                  .filter(trans -> trans.getChinese() < 60)
                                  .collect(Collectors.toList());
chineseNoPass.forEach(t -> System.out.println(t.getName()));

3. map的使用

再來,map的使用主要可以應用在,如有一字串型態的List,假設要將其轉換成大寫的List,

就可以利用map來撰寫了! 範例如下:

List<String> collected = Stream.of("ben", "sjkok", "jack", "aaron")
                               .map(string -> string.toUpperCase())
                               .collect(Collectors.toList());

在經由map的使用之後,stream內存放的物件將會被轉換成大寫的string

4. 混合的使用

最後,要舉的例子為如何得到平均分數大於80分的學生名單呢?

在這邊將混合filter、map、collect一起使用囉!
List<String> excellentName = studentList.stream()
            .filter(t -> {
             int sum = t.getChinese()+t.getEnglish()+t.getMath();
             return sum/3 > 80;
            })
            .map(t -> t.getName())
            .collect(Collectors.toList());
excellentName.forEach(name -> System.out.println(name));

在filter內先過濾掉低於80分的物件。再來由於我們只要取得學生的名字,因此可以利用

map來將目前存放於stream的Transcript物件轉換成String物件喔!!最後,將這些String物件

做collect回傳一List<String> 型態的list即大功告成囉!


參考資料   Java 8 Lamdas技術手冊

留言