Java8的四大函數式介面及相關的擴充套件介面在日常使用中的頻率也是非常多的,包括自己定義的函數式介面,在JDK1.8之前,我們定義的方法都是用來接收引數,然後自己根據引數傳遞實現邏輯。在1.8之後,可以通過引數傳遞一段行為程式碼,將公共的行為程式碼封裝成一個函數式介面傳遞,可以減少很多程式碼量,在Stream的API中就有很多的體現,在此歸納總結一下。
函數式介面指的是有且只能有一個抽象方法,但是可以有多個非抽象方法的介面,這樣的介面可以轉換成Lambda表示式。在函數式介面中,可以新增上@FunctionalInterface註解標註這是一個函數式介面,此註解主要用於編譯器在編譯期檢查該介面是否符合函數式介面的定義規範(即只能有一個抽象方法),如不符合,編譯器則會報錯提示。
原始碼如下,此介面中的抽象方法則是accept,傳入一個T引數,執行自定義邏輯將它消費掉,沒有返回值。
@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); }; } }
範例,實現一個列印List的Consumer介面,傳入不同的List將其列印。
有沒有機智的同學發現,範例中的forEach()方法其引數就是一個Consumer介面,根據傳入的集合將其遍歷。
Consumer介面在JDK中的應用,此為Iterable介面中的forEach方法,ArrayList中的forEach就是重寫了該方法。
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
原始碼如下,此介面中方法只有一個無參的方法,返回一個T型別的結果。
@FunctionalInterface public interface Supplier<T> { T get(); }
範例,實現一個返回亂數的Supplier介面,通過指定數量返回一個亂數集合。
Supplier介面在JDK中的應用,此為Optional類中的orElseGet方法。
public T orElseGet(Supplier<? extends T> other) { return value != null ? value : other.get(); }
原始碼如下,此介面中的抽象方法為apply,傳入一個T引數,返回一個R結果。
@FunctionalInterface public interface Function<T, R> { R apply(T t); default <V> Function<V, R> compose(Function<? super V, ? extends T> before) { Objects.requireNonNull(before); return (V v) -> apply(before.apply(v)); } default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) { Objects.requireNonNull(after); return (T t) -> after.apply(apply(t)); } static <T> Function<T, T> identity() { return t -> t; } }
範例,將字串使用MD5加密後返回。
Function介面在JDK中的應用,此為Stream中的map與flatMap方法。
<R> Stream<R> map(Function<? super T, ? extends R> mapper); <R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
原始碼如下,抽象方法為test,傳入一個T型別,返回一個固定型別為布林值的方法。
@FunctionalInterface public interface Predicate<T> { boolean test(T t); default Predicate<T> and(Predicate<? super T> other) { Objects.requireNonNull(other); return (t) -> test(t) && other.test(t); } default Predicate<T> negate() { return (t) -> !test(t); } default Predicate<T> or(Predicate<? super T> other) { Objects.requireNonNull(other); return (t) -> test(t) || other.test(t); } static <T> Predicate<T> isEqual(Object targetRef) { return (null == targetRef) ? Objects::isNull : object -> targetRef.equals(object); } }
範例,判斷數位是否大於0。
Predicate介面在JDK中的應用,此為Stream中的filter方法。
Stream<T> filter(Predicate<? super T> predicate);
熟悉使用Stream的靚仔們肯定知道,它極大簡化了我們的程式碼量,在其中就有很多頻繁應用函數式介面的地方。
以上就是四大內建核心函數式介面與各擴充套件介面的使用,可以涵蓋工作中大部分的業務場景。如還有不滿足業務場景的地方,hutool工具包中也有更多的擴充套件介面可使用,也可以自定義函數式介面,結合自身的業務使用,非常靈活強大,配合Lambda表示式和方法參照可以使程式碼更簡潔,省略冗餘的程式碼。
參考連結:
JDK8新特性第二篇:四大函數式介面【Function/Consumer/Supplier/Perdicate】、介面的擴充套件方法【default/static】