[翻译] 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