[譯]Java8:循環與函數式編程


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

*原創譯文


免責聲明!

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



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