介紹
函數式接口(Functional Interface)就是一個有且僅有一個抽象方法,但是可以有多個非抽象方法的接口。
函數式接口可以被隱式轉換為 lambda 表達式(箭頭函數)。
函數式接口代表的一種契約, 一種對某個特定函數類型的契約。
Lambda表達式不能脫離上下文而存在,它必須要有一個明確的目標類型(interface),而這個目標類型就是某個函數式接口。
java8之前已經存在的函數式接口有很多,比如java.lang.Runnable、java.util.concurrent.Callable、java.util.Comparator等。
而新增加的函數式接口都在java.util.function包下。
Java 不會強制要求你使用 @FunctionalInterface 注解來標記你的接口是函數式接口, 然而,作為API作者, 你可能傾向使用@FunctionalInterface指明特定的接口為函數式接口, 這只是一個設計上的考慮, 可以讓用戶很明顯的知道一個接口是函數式接口。
入門
先來看一個入門的例子就能明白為啥函數式接口是一種契約:
@FunctionalInterface public interface Predicate<T> { //該接口有一個抽象方法test,它接受一個參數t,並且返回boolean //如此定義一個抽象方法,就是在約定,我這個抽象方法的實現類,一定是僅有一個參數,並且只會返回一個boolean的值。 //所以說函數式接口是一種契約。 boolean test(T t); }
Predicate的使用實例:
//方法evel接受一個列表和一個Predicate接口 //list每個元素會當成 predicate的test方法的參數。 //因為函數式接口是可以使用Lambda表達式的,所以第二個參數這里就可以使用箭頭函數了。 public static void eval(List<Integer> list, Predicate<Integer> predicate) { //循環list for(Integer i: list) { //調用predicate的test方法,返回一個boolean值。 if(predicate.test(i)) { System.out.println(i + " "); } //疑問:Predicate是一個接口啊!那他具體執行的方法(實現類/實現方法)在哪里呢???? //請看main方法!!! } } public static void main(String args[]){ //定義一個list List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9); //n -> n%2 //其實很簡單,這個Lambda表達式其實就是Predicate接口的實現: // 箭頭左邊 n 是一個參數, 它會被傳遞到 Predicate 接口的 test 方法中 // 而箭頭右邊 n%2 其實就是這個 test 抽象方法的實現方法,它用來計算輸入參數是否是一個偶數。 //所以整個方法就是用來打印list中的偶數了。 eval(list, n-> n%2 == 0 ); System.out.println("輸出所有偶數:"); }
新函數式接口
java.util.function中定義了幾組類型的函數式接口以及針對基本數據類型的子接口。
- Predicate -- 傳入一個參數,返回一個bool結果, 方法為boolean test(T t)
- Consumer -- 傳入一個參數,無返回值,純消費。 方法為void accept(T t)
- Function -- 傳入一個參數,返回一個結果,方法為R apply(T t)
- Supplier -- 無參數傳入,返回一個結果,方法為T get()
- UnaryOperator -- 一元操作符, 繼承Function,傳入參數的類型和返回類型相同。
- BinaryOperator -- 二元操作符, 傳入的兩個參數的類型和返回類型相同, 繼承BiFunction
函數式接口中的抽象方法
在上面介紹中,說到函數式接口有且僅有一個抽象方法,其實是不正確的,因為函數式接口中可以額外定義多個抽象方法,但這些抽象方法簽名必須和Object類的 public方法一樣,只是我們一般不會再重新定義這些方法。
@FunctionalInterface public interface ObjectMethodFunctionalInterface { void count(int i); String toString(); //same to Object.toString int hashCode(); //same to Object.hashCode boolean equals(Object obj); //same to Object.equals }
聲明異常
函數式接口的抽象方法可以聲明 可檢查異常(checked exception)。 在調用目標對象的這個方法時必須catch這個異常。
@FunctionalInterface interface InterfaceWithException { //聲明異常 void apply(int i) throws Exception; }
捕獲異常:
public class FunctionalInterfaceWithException { public static void main(String[] args) { InterfaceWithException target = i -> {}; try { target.apply(10); } catch (Exception e) { e.printStackTrace(); } } }
非法拋出異常:
@FunctionalInterface interface InterfaceWithException { //沒有聲明異常 void apply(int i); } public class FunctionalInterfaceWithException { public static void main(String[] args) { //函數式接口沒有聲明異常, //而 Lambda中卻拋出了異常,此時是無法通過編譯的!!! InterfaceWithException target = i -> {throw new Exception();}; } }
靜態方法
函數式接口中除了那個抽象方法外還可以包含靜態方法。
Java 8以前的規范中接口中不允許定義靜態方法。 靜態方法只能在類中定義。 但是到了Java 8,可以定義靜態方法。
默認方法
Java 8中允許接口實現方法, 而不是簡單的聲明, 這些方法叫做默認方法,使用特殊的關鍵字default。
因為默認方法不是抽象方法,所以不影響我們判斷一個接口是否是函數式接口。
function包中的類的函數式接口概覽
-
BiConsumer<T,U> 代表了一個接受兩個輸入參數的操作,並且不返回任何結果
-
BiFunction<T,U,R> 代表了一個接受兩個輸入參數的方法,並且返回一個結果
-
BinaryOperator 代表了一個作用於於兩個同類型操作符的操作,並且返回了操作符同類型的結果
-
BiPredicate<T,U> 代表了一個兩個參數的boolean值方法
-
BooleanSupplier 代表了boolean值結果的提供方
-
Consumer 代表了接受一個輸入參數並且無返回的操作
-
DoubleBinaryOperator 代表了作用於兩個double值操作符的操作,並且返回了一個double值的結果。
-
DoubleConsumer 代表一個接受double值參數的操作,並且不返回結果。
-
DoubleFunction 代表接受一個double值參數的方法,並且返回結果
-
DoublePredicate 代表一個擁有double值參數的boolean值方法
-
DoubleSupplier 代表一個double值結構的提供方
-
DoubleToIntFunction 接受一個double類型輸入,返回一個int類型結果。
-
DoubleToLongFunction 接受一個double類型輸入,返回一個long類型結果
-
DoubleUnaryOperator 接受一個參數同為類型double,返回值類型也為double 。
-
Function<T,R> 接受一個輸入參數,返回一個結果。
-
IntBinaryOperator 接受兩個參數同為類型int,返回值類型也為int 。
-
IntConsumer 接受一個int類型的輸入參數,無返回值 。
-
IntFunction 接受一個int類型輸入參數,返回一個結果 。
-
IntPredicate :接受一個int輸入參數,返回一個布爾值的結果。
-
IntSupplier 無參數,返回一個int類型結果。
-
IntToDoubleFunction 接受一個int類型輸入,返回一個double類型結果 。
-
IntToLongFunction 接受一個int類型輸入,返回一個long類型結果。
-
IntUnaryOperator 接受一個參數同為類型int,返回值類型也為int 。
-
LongBinaryOperator 接受兩個參數同為類型long,返回值類型也為long。
-
LongConsumer 接受一個long類型的輸入參數,無返回值。
-
LongFunction 接受一個long類型輸入參數,返回一個結果。
-
LongPredicate R接受一個long輸入參數,返回一個布爾值類型結果。
-
LongSupplier 無參數,返回一個結果long類型的值。
-
LongToDoubleFunction 接受一個long類型輸入,返回一個double類型結果。
-
LongToIntFunction 接受一個long類型輸入,返回一個int類型結果。
-
LongUnaryOperator 接受一個參數同為類型long,返回值類型也為long。
-
ObjDoubleConsumer 接受一個object類型和一個double類型的輸入參數,無返回值。
-
ObjIntConsumer 接受一個object類型和一個int類型的輸入參數,無返回值。
-
ObjLongConsumer 接受一個object類型和一個long類型的輸入參數,無返回值。
-
Predicate 接受一個輸入參數,返回一個布爾值結果。
-
Supplier 無參數,返回一個結果。
-
ToDoubleBiFunction<T,U> 接受兩個輸入參數,返回一個double類型結果
-
ToDoubleFunction 接受一個輸入參數,返回一個double類型結果
-
ToIntBiFunction<T,U> 接受兩個輸入參數,返回一個int類型結果。
-
ToIntFunction 接受一個輸入參數,返回一個int類型結果。
-
ToLongBiFunction<T,U> 接受兩個輸入參數,返回一個long類型結果。
-
ToLongFunction 接受一個輸入參數,返回一個long類型結果。
-
UnaryOperator 接受一個參數為類型T,返回值類型也為T
作者:DoubleDragon
鏈接:https://juejin.im/post/5c77b354e51d457143522e13
來源:掘金