看板 Translate-CS 關於我們 聯絡資訊
原文網址: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/ -- 錢鍾書: 說出來的話 http://www.psmonkey.org 比不上不說出來的話 Java 版 cookcomic 版 只影射著說不出來的話 and more...... -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 114.25.29.173 Update:校正翻譯錯誤 ※ 編輯: PsMonkey 來自: 114.25.29.173 (04/03 15:22)