正如我以前所寫的,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)做爲返回集合。