java8函數式接口(Functional Interface)


介紹

函數式接口(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包中的類的函數式接口概覽

  1. BiConsumer<T,U> 代表了一個接受兩個輸入參數的操作,並且不返回任何結果

  2. BiFunction<T,U,R> 代表了一個接受兩個輸入參數的方法,並且返回一個結果

  3. BinaryOperator 代表了一個作用於於兩個同類型操作符的操作,並且返回了操作符同類型的結果

  4. BiPredicate<T,U> 代表了一個兩個參數的boolean值方法

  5. BooleanSupplier 代表了boolean值結果的提供方

  6. Consumer 代表了接受一個輸入參數並且無返回的操作

  7. DoubleBinaryOperator 代表了作用於兩個double值操作符的操作,並且返回了一個double值的結果。

  8. DoubleConsumer 代表一個接受double值參數的操作,並且不返回結果。

  9. DoubleFunction 代表接受一個double值參數的方法,並且返回結果

  10. DoublePredicate 代表一個擁有double值參數的boolean值方法

  11. DoubleSupplier 代表一個double值結構的提供方

  12. DoubleToIntFunction 接受一個double類型輸入,返回一個int類型結果。

  13. DoubleToLongFunction 接受一個double類型輸入,返回一個long類型結果

  14. DoubleUnaryOperator 接受一個參數同為類型double,返回值類型也為double 。

  15. Function<T,R> 接受一個輸入參數,返回一個結果。

  16. IntBinaryOperator 接受兩個參數同為類型int,返回值類型也為int 。

  17. IntConsumer 接受一個int類型的輸入參數,無返回值 。

  18. IntFunction 接受一個int類型輸入參數,返回一個結果 。

  19. IntPredicate :接受一個int輸入參數,返回一個布爾值的結果。

  20. IntSupplier 無參數,返回一個int類型結果。

  21. IntToDoubleFunction 接受一個int類型輸入,返回一個double類型結果 。

  22. IntToLongFunction 接受一個int類型輸入,返回一個long類型結果。

  23. IntUnaryOperator 接受一個參數同為類型int,返回值類型也為int 。

  24. LongBinaryOperator 接受兩個參數同為類型long,返回值類型也為long。

  25. LongConsumer 接受一個long類型的輸入參數,無返回值。

  26. LongFunction 接受一個long類型輸入參數,返回一個結果。

  27. LongPredicate R接受一個long輸入參數,返回一個布爾值類型結果。

  28. LongSupplier 無參數,返回一個結果long類型的值。

  29. LongToDoubleFunction 接受一個long類型輸入,返回一個double類型結果。

  30. LongToIntFunction 接受一個long類型輸入,返回一個int類型結果。

  31. LongUnaryOperator 接受一個參數同為類型long,返回值類型也為long。

  32. ObjDoubleConsumer 接受一個object類型和一個double類型的輸入參數,無返回值。

  33. ObjIntConsumer 接受一個object類型和一個int類型的輸入參數,無返回值。

  34. ObjLongConsumer 接受一個object類型和一個long類型的輸入參數,無返回值。

  35. Predicate 接受一個輸入參數,返回一個布爾值結果。

  36. Supplier 無參數,返回一個結果。

  37. ToDoubleBiFunction<T,U> 接受兩個輸入參數,返回一個double類型結果

  38. ToDoubleFunction 接受一個輸入參數,返回一個double類型結果

  39. ToIntBiFunction<T,U> 接受兩個輸入參數,返回一個int類型結果。

  40. ToIntFunction 接受一個輸入參數,返回一個int類型結果。

  41. ToLongBiFunction<T,U> 接受兩個輸入參數,返回一個long類型結果。

  42. ToLongFunction 接受一個輸入參數,返回一個long類型結果。

  43. UnaryOperator 接受一個參數為類型T,返回值類型也為T


作者:DoubleDragon
鏈接:https://juejin.im/post/5c77b354e51d457143522e13
來源:掘金


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM