Java8-5-Function函數式接口進階與默認方法詳解

Java8-5-函數式接口進階與默認方法詳解
上一篇咱們快速的藉助示例演示了stream api的簡單應用,體會到了使用stream api對集合處理的便捷和其與函數式接口密不可分的關係,因此爲了更高效的使用stream api,有必要更熟練的掌握函數式接口。Java8中內置了大量的函數式接口,接下來咱們選擇一些比較經常使用的一塊兒學習下。html

Function接口
在以前的文章中,咱們簡單介紹過Function接口中apply方法的應用,除了apply這個抽象方法,Function接口中還內置了兩個比較經常使用的默認方法(接口中增長的有具體實現的方法,擴展了接口功能,子類默認會繼承該實現),看下Function接口源碼segmentfault

/**
 * Represents a function that accepts one argument and produces a result.
 *
 * <p>This is a <a href="package-summary.html">functional interface</a>
 * whose functional method is {@link #apply(Object)}.
 *
 * @param <T> the type of the input to the function
 * @param <R> the type of the result of the function
 *
 * @since 1.8
 */
@FunctionalInterface
public interface Function<T, R> {

    R apply(T t);

    /**
     * @return a composed function that first applies the {@code before}
     * function and then applies this function
     */
    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
        Objects.requireNonNull(before);
        return (V v) -> apply(before.apply(v));
    }
    /**
     * @return a composed function that first applies this function and then
     * applies the {@code after} function
     */
    default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t) -> after.apply(apply(t));
    }
    /**
     * 省略
     */
}

Function接口定義中有兩個泛型,按着接口文檔說明第一個泛型是輸入類型,第二泛型是結果類型。
compose方法接收一個Function參數before,該方法說明是返回一個組合的函數,首先會應用before,而後應用當前對象,換句話說就是先執行before對象的apply,再執行當前對象的apply,將兩個執行邏輯串起來。
andThen方法接收一個Function參數after,與compose方法相反,它是先執行當前對象的apply方法,再執行after對象的方法。看一個應用示例api

public class FunctionTest {
    public static void main(String[] args) {
        FunctionTest functionTest = new FunctionTest();
        System.out.println(functionTest.compute1(5,i -> i * 2,i -> i * i));//50
        System.out.println(functionTest.compute2(5,i -> i * 2,i -> i * i));//100
    }

    public int compute1(int i, Function<Integer,Integer> after,Function<Integer,Integer> before){
        return after.compose(before).apply(i);
    }

    public int compute2(int i, Function<Integer,Integer> before,Function<Integer,Integer> after){
        return before.andThen(after).apply(i);
    }
}

定義了compute1和compute2兩個方法,compute1方法第一個參數是要計算的數據,第二個參數是後執行的函數,第一個是先執行的函數,由於輸入輸出都是數字類型,因此泛型都指定爲Integer類型,經過after.compose(before);將兩個函數串聯起來而後執行組合後的Funtion方法apply(i)。當調用compute1(5,i -> i 2,i -> i i)時,先平方再乘以2因此結果是50。而compute2方法對兩個Function的調用正好相反,因此結果是100。數組

BiFunction接口
接下來繼續看下另外一個很經常使用的函數式接口BiFunctionapp

/**
 * This is the two-arity specialization of {@link Function}.
 * @param <T> the type of the first argument to the function
 * @param <U> the type of the second argument to the function
 * @param <R> the type of the result of the function
 *
 * @see Function
 * @since 1.8
 */
@FunctionalInterface
public interface BiFunction<T, U, R> {

    /**
     * Applies this function to the given arguments.
     *
     * @param t the first function argument
     * @param u the second function argument
     * @return the function result
     */
    R apply(T t, U u);

    /**
     * Returns a composed function that first applies this function to
     * its input, and then applies the {@code after} function to the result.
     * If evaluation of either function throws an exception, it is relayed to
     * the caller of the composed function.
     *
     * @param <V> the type of output of the {@code after} function, and of the
     *           composed function
     * @param after the function to apply after this function is applied
     * @return a composed function that first applies this function and then
     * applies the {@code after} function
     * @throws NullPointerException if after is null
     */
    default <V> BiFunction<T, U, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t, U u) -> after.apply(apply(t, u));
    }
}

實際上就是能夠有兩個參數的Function,一樣前兩個泛型表明着入參的類型,第三個表明結果類型。函數

public class BiFunctionTest {
    public static void main(String[] args) {
        BiFunctionTest2 biFunctionTest2 = new BiFunctionTest2();
        System.out.println(biFunctionTest2.compute(4,5,(a,b) -> a * b,a -> a * 2));
    }

    public int compute(int a, int b, BiFunction<Integer,Integer,Integer> biFunction,
                       Function<Integer,Integer> function){
        return biFunction.andThen(function).apply(a,b);
    }
}

看下compute方法,前兩個參數是待計算數據,第三個是一個BiFunction,由於入參和結果都是數組因此三個泛型都定義爲Integer。最後一個參數是Function。計算邏輯是先執行BiFunction而後將結果傳給Funciton在計算最後返回結果,因此使用了andThen方法。咱們想一下,BiFunction的andThen方法爲何接收的是Function類型的參數而不是BiFunction,答案很簡單,由於BiFunction的apply方法接收兩個參數,可是任何一個方法不可能有兩個返回值,因此也沒辦法放在BiFunction前面執行,這也是爲何BiFunction沒有compose方法的緣由。學習

下一篇ui

相關文章
相關標籤/搜索