Java 8:使用compose和andThen組合函數
在這篇文章中,我將討論利用 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 來使用簡單的方式組合功能。你也試試吧!