正如我以前所写的,Java 8中的新功能特性改变了游戏规则。对Java开发者来讲这是一个全新的世界,而且是时候去适应它了。html
在这篇文章里,咱们将会去了解传统循环的一些替代方案。在Java 8的新功能特性中,最棒的特性就是容许咱们去表达咱们想要完成什么而不是要怎样作。这正是循环的不足之处。要确保循环的灵活性是须要付出代价的。return、break 或者 continue都会显著地改变循环的实际表现。这迫使咱们不只要清楚咱们要实现怎样的代码,还要了解循环是怎样工做的。java
在介绍Java 8的流(Stream)时,咱们学会了一些集合操做的实用技巧。如今咱们要看看怎样把这些循环转换为更简洁,可读性更高的代码。api
好吧,讲的够多了,是时候展现一些例子了!oracle
此次咱们要以文章为例子。一篇文章拥有一个标题,一个做者和几个标签。this
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
private
class
Article {
private
final
String title;
private
final
String author;
private
final
List<String> tags;
private
Article(String title, String author, List<String> tags) {
this
.title = title;
this
.author = author;
this
.tags = tags;
}
public
String getTitle() {
return
title;
}
public
String getAuthor() {
return
author;
}
public
List<String> getTags() {
return
tags;
}
}
|
每一个例子都会包含一个使用传统循环的方案和一个使用Java 8新特性的方案。编码
在第一个例子里,咱们要在集合中查找包含“Java”标签的第一篇文章。spa
看一下使用for循环的解决方案。code
1
2
3
4
5
6
7
8
9
10
|
public
Article getFirstJavaArticle() {
for
(Article article : articles) {
if
(article.getTags().contains(
"Java"
)) {
return
article;
}
}
return
null
;
}
|
如今咱们使用Stream API的相关操做来解决这个问题。htm
1
2
3
4
5
|
public
Optional<Article> getFirstJavaArticle() {
return
articles.stream()
.filter(article -> article.getTags().contains(
"Java"
))
.findFirst();
}
|
是否是很酷?咱们首先使用 filter 操做去找到全部包含Java标签的文章,而后使用 findFirst() 操做去获取第一次出现的文章。由于Stream是“延迟计算”(lazy)的而且filter返回一个流对象,因此这个方法仅在找到第一个匹配元素时才会处理元素。对象
如今,让咱们获取全部匹配的元素而不是仅获取第一个。
首先使用for循环方案。
1
2
3
4
5
6
7
8
9
10
11
12
|
public
List<Article> getAllJavaArticles() {
List<Article> result =
new
ArrayList<>();
for
(Article article : articles) {
if
(article.getTags().contains(
"Java"
)) {
result.add(article);
}
}
return
result;
}
|
使用Stream操做的方案。
1
2
3
4
5
|
public
List<Article> getAllJavaArticles() {
return
articles.stream()
.filter(article -> article.getTags().contains(
"Java"
))
.collect(Collectors.toList());
}
|
在这个例子里咱们使用 collection 操做在返回流上执行少许代码而不是手动声明一个集合并显式地添加匹配的文章到集合里。
到目前为止还不错。是时候举一些突出Stream API强大的例子了。
根据做者来把全部的文章分组。
照旧,咱们使用循环方案。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
public
Map<String, List<Article>> groupByAuthor() {
Map<String, List<Article>> result =
new
HashMap<>();
for
(Article article : articles) {
if
(result.containsKey(article.getAuthor())) {
result.get(article.getAuthor()).add(article);
}
else
{
ArrayList<Article> articles =
new
ArrayList<>();
articles.add(article);
result.put(article.getAuthor(), articles);
}
}
return
result;
}
|
咱们可否找到一个使用流操做的简洁方案来解决这个问题?
1
2
3
4
|
public
Map<String, List<Article>> groupByAuthor() {
return
articles.stream()
.collect(Collectors.groupingBy(Article::getAuthor));
}
|
很好!使用 groupingBy 操做和 getAuthor 方法,咱们获得了更简洁、可读性更高的代码。
如今,咱们查找集合中全部不一样的标签。
咱们从使用循环的例子开始。
1
2
3
4
5
6
7
8
9
10
|
public
Set<String> getDistinctTags() {
Set<String> result =
new
HashSet<>();
for
(Article article : articles) {
result.addAll(article.getTags());
}
return
result;
}
|
好,咱们来看看如何使用Stream操做来解决这个问题。
1
2
3
4
5
|
public
Set<String> getDistinctTags() {
return
articles.stream()
.flatMap(article -> article.getTags().stream())
.collect(Collectors.toSet());
}
|
棒极了!flatmap 帮我把标签列表转为一个返回流,而后咱们使用 collect 去建立一个集合做为返回值。
以上的就是如何使用可读性更高的代码代替循环的例子。务必仔细看看Stream API,由于这篇文章仅仅提到它的一些皮毛而已。
收到solarfuse和dhruvgairola的评论后,更新了getDistinctTags()例子,使用集合(Set)做为返回集合。