天天看點

JDK8 新特性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 代碼如下圖:

JDK8 新特性Function接口

我覺得兩種方式都是給 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。

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