[翻譯] Java 8 取出 Collection element 的方式

作者: PsMonkey (痞子軍團團長)   2013-04-03 12:42:59
原文網址:http://www.javacodegeeks.com/2013/03/
extracting-the-elements-of-the-java-collection-the-java-8-way.html
譯文網址:http://blog.dontcareabout.us/2013/04/java-8-collection-element.html
BBS 使用 markdown 格式撰寫
譯文中的 Collection,代表 Collection API
或是屬於 Collection 的各個 class(List、Map...)。
如果是 collection,則代表某個 Collection 的 instance。
______________________________________________________________________
我們都廣泛使用 Collection,
像是 `List`、`Map` 以及延伸的 class。
每次我們用的時候,我們都得掃遍整個 collection 去找到某些 element、
更新它們、或是找出某個條件下不同的 element。
就像下面這個 `Person` 的 `List`:
List<Person> personList = new ArrayList<>();
personList.add(new Person("Virat", "Kohli",22));
personList.add(new Person("Arun", "Kumar",25));
personList.add(new Person("Rajesh", "Mohan", 32));
personList.add(new Person("Rahul", "Dravid", 35));
要找出 `Person` 的年齡大於 30 的 instance,我們會這樣作:
List<Person> olderThan30OldWay = new ArrayList<>();
for ( Person p : personList){
if ( p.age >= 30){
olderThan30OldWay.add(p);
}
}
System.out.println(olderThan30OldWay);
就會得到這樣的輸出結果:
[Rajesh Mohan, 32, Rahul Dravid, 35]
程式碼是很好寫,但會不會有點囉唆、尤其是迴圈的部份?
為甚麼我們得要有迴圈呢?
如果有 API 可以掃描內容、然後給我們最終結果,
例如我們給一個 `List`、然後用一串 method 之後
就可以取得我們想要的 `List` 結果?
有的,在 Scala、Groovy 這種有支援 closure、
也支援內部迴圈的語言就有可能做到。
但是有給 Java 開發人員的解決方案嗎?
有的,這個問題在導入 [Lambda Expression(closure)] 後,
利用 lambda expression 來 [加強 Collection API][sotc3],就可以解決。
不過壞消息是,這會是 Java 8 的一部分,
[需要一點時間]才會變成主流的開發方式。
[Lambda Expression(closure)]: http://openjdk.java.net/projects/lambda/
[sotc3]: http://cr.openjdk.java.net/~briangoetz/lambda/sotc3.html
[需要一點時間]: http://openjdk.java.net/projects/jdk8/milestones
在上面的情境中使用 Java 8 的強化功能
====================================
正如我知前所說,Collection API 正在補強以支援 lambda expression,
你可以在[這篇文章][sotc3]中了解更多內容。
JDK 團隊並不是把所有新的 API 加到 Collection 當中,
而是創造了一個新的概念 `Stream`,
並且把大部分的 API 加到那個 class 當中。
`Stream` 是 element 的序列,在建立時從 collection 取得。
要了解更多 `Stream` 的起源,請參考[這篇文章][sotc3]。
要實作這個範例,我開始使用 Java 8 的強化功能、一些新的 API:
`stream()`、`filter()`、`collect()`、`Collectior.toCollection()`。
* [stream()]:collection 用這個 API 可以建立一個 [Stream] 的 instance。
* [filter()]:這個 method 接收一個
會回傳 boolean 值的 lambda expression。
這個 lambda expression 會替換成 [Predicate] class 的實作。
* [collect()]:有兩個 overloaded 的版本。我在這邊用其中一個,
可以取得 [Collector] 的 instance。
這個 method 會取得 stream 的內容然後建立另一個 collection,
建立的邏輯在 [Collector] 當中定義。
* [Collectors.toCollection()][toCollection()]:
[Collectors] 是 [Collector] 的 factory(pattern)。
[toCollection()] 需要一個可以回傳任何 Collection class instance
的 lambda expression / method reference。
[stream()]: http://download.java.net/lambda/b81/docs/api/
java/util/Collection.html#stream()
[Stream]: http://download.java.net/lambda/b81/docs/api/
java/util/stream/Stream.html
[filter()]: http://download.java.net/lambda/b81/docs/api/
java/util/stream/Stream.html#filter(java.util.function.Predicate)
[Predicate]: http://download.java.net/lambda/b81/docs/api/
java/util/function/Predicate.html
[collect()]: http://download.java.net/lambda/b81/docs/api/
java/util/stream/Stream.html#collect(java.util.stream.Collector)
[Collector]: http://download.java.net/lambda/b81/docs/api/
java/util/stream/Collector.html
[toCollection()]: http://download.java.net/lambda/b81/docs/api/
java/util/stream/Collectors.html
#toCollection(java.util.function.Supplier)
[Collectors]: http://download.java.net/lambda/b81/docs/api/
java/util/stream/Collectors.html
簡單介紹要用的 API 之後,讓我來展示一下跟第一個範例等意的程式碼:
List<Person> olderThan30 =
//Create a Stream from the personList
personList.stream().
//filter the element to select only those with age >= 30
filter(p -> p.age >= 30).
//put those filtered elements into a new List.
collect(Collectors.toCollection(() -> new ArrayList<Person>()));
System.out.println(olderThan30);
上面的程式碼使用內部迴圈以及 lambda expression
讓它看起來直覺、簡潔、還可以舒緩眼睛不適。
(譯註:我承認最後一個是惡搞亂翻的 [逃])
如果你不熟悉 lambda expression 的想法,
可以看一下我[之前寫的文章],裡頭有簡單的介紹。
[之前寫的文章]: http://blog.sanaulla.info/2013/03/11/
using-lambda-expression-to-sort-a-list-in-java-8
-using-netbeans-lambda-support/

Links booklink

Contact Us: admin [ a t ] ucptt.com