Java8函數式編程的加入徹底改變了游戲規則。對Java開發者來說這是一個全新的世界,我們也需要做出相應的改變。
在這篇文章中我們將找尋傳統循環代碼的可替代方案。Java8的函數式編程特性改變了編程思路,從 “我們怎樣去做” 變成了 “我們想做什么” 。這也是傳統循環的缺點。當然傳統循環更加的靈活,但其靈活性並不能掩蓋他的問題。return、break、continue能直接改變循環的執行流程,強迫我們不僅要理解業務邏輯,同時也要了解循環是怎樣工作的。
Java8通過引入stream指令,我們可以在集合上使用強大的函數式操作。現在我們來看看怎樣將傳統循環轉變為更簡潔,更具有可讀性的代碼。
這里將會創建一個Article類,他有三個成員變量:title、author、tags:
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; } }
每個例子都會包括一個傳統循環的解決方案,和Java8函數式編程的解決方案。
在第一個例子里面,將會在Article集合中尋找tag包含"Java"的第一個對象:
傳統循環的解決方案:
public Article getFirstJavaArticle(){ for(Article article : articles){ if(article.getTags().contains("Java")){ return article; } } return null; }
Java8的解決方案:
public Optional<String> getFirstJavaArticle(){ return articles.stream().filter(article -> article.getTags.contains("Java")).findFirst(); }
首先我們使用filter操作找到所有符合條件的Article,然后調用findFirst()方法得到第一個。因為stream是惰性的而且filter返回了一個stream,因此方法只有在找到第一個匹配時才會去處理這個元素。
現在讓我們嘗試獲取所有匹配的元素。
傳統循環解決方案:
public List<Article> getAllJavaArticles() { List<Article> result = new ArrayList<>(); for (Article article : articles) { if (article.getTags().contains("Java")) { result.add(article); } } return result; }
Java8解決方案:
public List<Article> getAllJavaArticles() { return articles.stream().filter(article -> article.getTags.contains("Java")).collect(Collectors.toList()); }
在這個例子中我們使用了 collect 方法去篩選stream,而不是自己聲明一個集合,並將匹配的參數追加到集合中。
到目前為止都不錯,現在是時候來展現 stream api真正的魅力了!
讓我們基於author將articles進行分組。
傳統循環解決方案:
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); } } }
Java8解決方案:
public Map<String, List<Article>> groupByAuthor() { return articles.stream().collect(Collectors.groupingBy(Article::getAuthor)); }
通過使用groupingBy操作和getAuthor的方法引用,我們得到了整潔並且可讀性高的代碼。
現在,讓我們在集合中找到Article所有的不重復的tags。
首先時傳統循環方案:
public Set<String> getDistinctTags(){ Set<String> result = new HashSet<>(); for(Article article : articles){ result.addAll(article.getTags()); } return result; }
Java8解決方案:
public Set<String> getDistinctTags(){ return articles.stream().flatMap(article -> article.getTags().stream()).collect(Collectors.toSet()); }
flatMap幫助我們獲取結果流中的tag集合,然后用collect方法創建一個Set並返回結果。
函數式編程擁有無限的可能,這四個例子的目的是怎樣將循環替換成更可讀的代碼。你應該仔細查看stream API,因為相比api這文章僅僅只是皮毛而已。
*英文鏈接:deadCodeRising
*原創譯文