JDK提供了大量的函數式接口,方便咱們開發的時候無需本身編寫接口,這些接口都比較通用,學會他們而且在工做中使用,不只方便的解決問題,並且十分優雅。
Consumer
接口也比較簡單,只有兩個方法,一個是抽象方法,一個是默認方法:數據庫
@FunctionalInterface public interface Consumer<T> { void accept(T t); default Consumer<T> andThen(Consumer<? super T> after){ Objects.requireNonNull(after); return (T t) -> { accept(t); after.accept(t); }; } }
accept
方法該方法接收一個接口泛型類型的對象,沒有返回值。設計模式
看看集合的 forEach
方法的使用:函數
public class ConsumerTest { public static void main(String[] args) { List<String> names = new ArrayList<String>() { { add("Tom"); add("Jerry"); } }; names.forEach(e -> System.out.println(e)); names.forEach(System.out::println); } }
咱們使用 forEach
方法的時候,該方法就是使用了 Consumer
接口做爲參數。這是咱們最多見的使用 Consumer
的方式。ui
除了打印信息,通常咱們對於集合中的對象的某些數據須要更改,也常常使用forEach 遍歷,而後對於每一個對象作一些業務操做。this
雖然 forEach
經常使用,可是通常咱們都不多關注 forEach
的實現,也不多本身寫個方法用到 Consumer
接口:設計
default void forEach(Consumer<? super T> action) { Objects.requireNonNull(action); for (T t : this) { action.accept(t); } }
public class ConsumerTest { private static final Map<Integer, String> map = new HashMap<Integer, String>() { { put(10, "Tom"); put(3, "Jerry"); } }; public static void main(String[] args) { //調用方法,同時編寫對結果的回調:此處僅僅打印而已 test(3, System.out::println); } public static void test(Integer age, Consumer<String> consumer) { //業務處理 System.out.println(age); //對處理結果的回調:下面的ifPresent參數也是Consumer接口,全部下面三種寫法均可以 //Optional.ofNullable(map.get(age)).ifPresent(e -> consumer.accept(e)); //Optional.ofNullable(map.get(age)).ifPresent(consumer::accept); Optional.ofNullable(map.get(age)).ifPresent(consumer); } }
Consumer
接口通常做爲方法參數來實現回調的功能,例如上面的例子,test
函數傳遞待處理的對象 age
,通過業務處理獲得其它結果對象,以後調用 accept
對結果對象進行處理。code
實際中回調處理的對象是根據入參獲得其它結果。好比傳入姓名從數據庫查詢數據,回調函數將數據保存在其它地方,那麼這個其它地方就須要調用者本身處理,好比存文件。對象
方法源碼:接口
default Consumer<T> andThen(Consumer<? super T> after) { Objects.requireNonNull(after); return (T t) -> { accept(t); after.accept(t); }; }
使用場景:開發
public static void main(String[] args) { Consumer<String> first = (x) -> System.out.println(x.toLowerCase()); Consumer<String> next = (x) -> System.out.println(x.toUpperCase()); first.andThen(next).accept("Hello World"); }
andThen 接收一個 Consumer 接口,返回的也是一個 Consumer 接口,一樣的,調用該方法的也是 Consumer 接口。這個地方比較繞,須要對照上面兩處代碼仔細分析。
first
是一個 Consumer
接口,當調用 andThen
方法的時候,並非執行 (T t) -> { accept(t); after.accept(t); }
這段代碼,而是返回了一個 Consumer
接口,注意它的結構是 給一個對象 t,而後大括號中消費 t 。 處理邏輯是當前 Consumer
執行 accept
方法,而後再讓 after
這個 Consumer
執行 accept
方法。理解 andThen
方法返回的結構特別重要。
當first.andThen(next)
執行完成,獲得一個 Consumer
接口接口後,再次調用 accept("Hello World")
時,實際上對 Hello World 字符串執行的內容就是大括號裏面的內容了:accept(t); after.accept(t);
也就是上面的先輸出小寫字符串、再輸出大寫的字符串了。
public class ConsumerTest { private static final Map<Integer, Consumer<String>> QUEUE = new ConcurrentHashMap<>(); public static void main(String[] args) { resolve(1, s -> System.out.println(s.toUpperCase())); resolve(1, s -> System.out.println(s.toLowerCase())); resolve(1, s -> System.out.println(s.substring(0, 2))); QUEUE.get(1).accept("Hello World"); } public static void resolve(Integer id, Consumer<String> callback) { final Consumer<String> existing = QUEUE.get(id); if (callback == null) callback = i -> {}; if (existing != null && callback != existing) { callback = existing.andThen(callback); } QUEUE.put(id, callback); } }
結果以下:
HELLO WORLD
hello world
He
上面代碼中的 resolve 方法根據 id , 向 map 類型的 QUEUE 中增長多個回調函數,最後執行的時候,多個回調函數都被執行,很相似責任鏈的設計模式。能夠結合上面的講解仔細理解
callback = existing.andThen(callback);
以及在執行的地方:
QUEUE.get(1).accept("Hello World");