1. 程式人生 > >JDK8 新特性 java.util.function Function介面

JDK8 新特性 java.util.function Function介面

參考部落格 : JDK8新特性-java.util.function-Function介面
原始碼(刪除了原始碼註釋):

package java.util.function;

import java.util.Objects;
 
@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;
    }
}

標註為 @FunctionalInterface 的介面被稱為函式式介面,該介面只能有一個抽象方法。如果一個介面只有一個抽象方法,則編譯器會認為這就是一個函式式介面。是否是一個函式式介面,需要注意的有以下幾點:

  • 該註解只能標記在”有且僅有一個抽象方法”的介面上。
  • JDK8 介面中的靜態方法和預設方法,都不是抽象方法。
  • 介面預設繼承 java.lang.Object,所以如果介面顯示宣告覆蓋了 Object 中的方法,那麼也不算抽象方法。
  • 該註解不是必須的,如果一個介面符合”函式式介面”定義,那麼加不加該註解都沒有影響。加上該註解能夠更好地讓編譯器進行檢查。如果編寫的不是函式式介面(比如有多個抽象方法),但是加上了@FunctionInterface,那麼編譯器會報錯。
    報錯如下圖:
    在這裡插入圖片描述

報錯程式碼如下:

package test;

import java.util.function.Function;

@FunctionalInterface
public interface myFunction extends Function<String , Integer> {

    Integer testFunctionalInterface();
}

因為 myFunction 介面繼承了 Function 介面,Function 接口裡面本來就定義了一個 apply() 抽象方法,因為 myFunction 介面又定義了一個抽象方法,所以不符合”函式式介面”定義了,加上 @FunctionalInterface,就會報錯。

使用 Function 介面:

  1. 使用 lambda 表示式直接賦值
Function<String , Integer> get_length = (String s) -> {
            return s.length();
};
Function<String , String> append = (String s) -> s.concat(" kaven!");
  1. 匿名類實現
Function<Integer , Integer> add = new Function<Integer, Integer>() {
            @Override
            public Integer apply(Integer integer) {
                return integer+100;
            }
};

生成的 class 程式碼如下圖:
在這裡插入圖片描述
我覺得兩種方式都是給 Function 介面的 apply() 抽象方法進行定義。

測試程式碼如下:

package test;

import java.util.function.Function;

public class testFunction {
    public static void main(String[] args){
        Function<String , Integer> get_length = (String s) -> {
            return s.length();
        };
        Function<String , String> append = (String s) -> s.concat(" kaven!");

        System.out.println(append.apply("Welcome"));
        System.out.println(get_length.compose(append).apply("Welcome"));
        System.out.println(append.andThen(get_length).apply("Welcome"));

        Function<Integer , Integer> add = new Function<Integer, Integer>() {
            @Override
            public Integer apply(Integer integer) {
                return integer+100;
            }
        };
        System.out.println(add.apply(100));

        System.out.println(Function.identity().apply("Kaven"));
    }
}

輸出資料如下:

Welcome kaven!
14
14
200
Kaven
System.out.println(get_length.compose(append).apply("Welcome"));
System.out.println(append.andThen(get_length).apply("Welcome"));

這兩行程式碼的效果是一樣的,先呼叫 append 的 apply() 方法,後呼叫get_length 的 apply() 方法。
原始碼也可以看出來:

default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
        Objects.requireNonNull(before);
        return (V v) -> apply(before.apply(v));//先呼叫 before 的 apply() 方法,後呼叫 this 的 apply() 方法。
}

default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t) -> after.apply(apply(t));//先呼叫 this 的 apply() 方法,後呼叫 after 的 apply() 方法。
}
static <T> Function<T, T> identity() {
        return t -> t;
}

Function 介面的靜態方法,返回一個 Function<T, T> 例項,並且給這個例項的 apply() 抽象方法賦值了一個 lambda 表示式 t -> t。所以呼叫 apply(“Kaven”),就會輸出 Kaven。

Function 介面可以搭配 BiFunction 介面一起使用(看原始碼就很清楚了,也刪除了原始碼註釋):

package java.util.function;

import java.util.Objects;

@FunctionalInterface
public interface BiFunction<T, U, R> {

    R apply(T t, U u);

    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));
    }
}