Java 8:不要再用循環了 Stream替代for循環


原文:http://www.importnew.com/14841.html

 

在這篇文章里,我們將會去了解傳統循環的一些替代方案。在Java 8的新功能特性中,最棒的特性就是允許我們去表達我們想要完成什么而不是要怎樣做。這正是循環的不足之處。要確保循環的靈活性是需要付出代價的。return、break 或者 continue都會顯著地改變循環的實際表現。這迫使我們不僅要清楚我們要實現怎樣的代碼,還要了解循環是怎樣工作的。

在介紹Java 8的流(Stream)時,我們學會了一些集合操作的實用技巧。現在我們要看看怎樣把這些循環轉換為更簡潔,可讀性更高的代碼。

開始編碼!

好吧,講的夠多了,是時候展示一些例子了!

這次我們要以文章為例子。一篇文章擁有一個標題,一個作者和幾個標簽。

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”標簽的第一篇文章。

看一下使用for循環的解決方案。

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的相關操作來解決這個問題。

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,因為這篇文章僅僅提到它的一些皮毛而已。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM