Java 8:使用compose和andThen組合函式

ImportNew發表於2015-12-20

在這篇文章中,我將討論利用 Function 介面提供的兩個組合函式—— compose 和 andThen 來實現函式的組合。

什麼是函式組合?

首先需要建立一些小的可重用函式,然後將這些小函式組合為新函式。

現在,我們怎麼利用 compose 和 andThen 方法來完成函式的組合?

首先,定義兩個簡單的函式—— times2 和 squared。

Function<Integer, Integer> times2 = e -> e * 2;

Function<Integer, Integer> squared = e -> e * e;

接下來,使用 compose 和 andThen 將它們連起來。

times2.compose(squared).apply(4);  
// Returns 32

times2.andThen(squared).apply(4);  
// Returns 64

如你所見,compose 和 andThen 的不同之處是函式執行的順序不同。compose 函式先執行引數,然後執行呼叫者,而 andThen 先執行呼叫者,然後再執行引數。

我們開始組合函式

我們先建立一個示例,演示如何利用這種方式建立可重用的小程式碼片段——然後我們以不同的方式組合這些程式碼片段。

考慮下面的問題。

有一個文章列表,現在需要根據不同的需求來過濾這些文章。

首先,我們介紹兩個基本功能—— byAuthor 和 byTag——基於作者和標籤來過濾文章。

BiFunction<String, List<Article>, List<Article>> byAuthor =
    (name, articles) -> articles.stream()
        .filter(a -> a.getAuthor().equals(name))
        .collect(Collectors.toList());

BiFunction<String, List<Article>, List<Article>> byTag =  
    (tag, articles) -> articles.stream()
        .filter(a -> a.getTags().contains(tag))
        .collect(Collectors.toList());

兩個函式都是 BiFunction——意味著需要兩個引數。

byAuthor 接收作者名稱和文章列表兩個引數,返回根據作者過濾後的文章列表。

byTag 與此相同,接收標籤和文章列表兩個引數,返回根據標籤過濾後的文章列表。

由於 BiFunction 接收兩個引數,它只提供 andThen 函式。你不能將一個函式的結果放在一個接收兩個引數的函式中,因此沒有 compose 函式。

繼續,我們還有一個基本功能,需對文章列表從新到舊進行排序,並返回排序後的文章列表。

Function<List<Article>, List<Article>> sortByDate =  
    articles -> articles.stream()
        .sorted((x, y) -> y.published().compareTo(x.published()))
        .collect(Collectors.toList());

Function<List<Article>, Optional<Article>> first =  
    a -> a.stream().findFirst();

現在,我們已經有了基本的函式,現在看我們怎麼利用這些函式來組合成新的函式。

首先,我們組合一個返回最近發表的文章列表函式。

Function<List<Article>, Optional<Article>> newest =  
    first.compose(sortByDate);

使用 first 這個函式以及我們之前建立的 sortByDate,我們能建立一個新的函式,該函式返回給定文章列表的最新文章。

我們可以繼續通過不同的方式混合這些函式,從而可以組合出不同意義的函式,而不需要重複寫程式碼。

找出作者的最新文章:

BiFunction<String, List<Article>, Optional<Article>> newestByAuthor =  
    byAuthor.andThen(newest);

或者對某一作者的文章進行排序

BiFunction<String, List<Article>, List<Article>> byAuthorSorted =  
    byAuthor.andThen(sortByDate);

或者你可能不關心作者,只想根據你喜歡標籤獲取最新的文章:

BiFunction<String, List<Article>, Optional<Article>> newestByTag =  
    byTag.andThen(newest);

我想要表達的觀點是:通過 Function 介面及其組合功能,可以建立小的程式碼塊,再將其組合來滿足你的需求,這樣可以可以更簡單、更有意思地實現 DRY 原則。

就這樣了——利用 compose 和 andThen 來使用簡單的方式組合功能。你也試試吧!

相關文章