java8函數式接口(Functional Interface),一篇摳腳都能懂的入門文章

介紹

函數式接口(Functional Interface)就是一個有且僅有一個抽象方法,可是能夠有多個非抽象方法的接口。java

函數式接口能夠被隱式轉換爲 lambda 表達式(箭頭函數)。app

函數式接口表明的一種契約, 一種對某個特定函數類型的契約。
Lambda表達式不能脫離上下文而存在,它必需要有一個明確的目標類型(interface),而這個目標類型就是某個函數式接口。函數

java8以前已經存在的函數式接口有不少,好比java.lang.Runnable、java.util.concurrent.Callable、java.util.Comparator等。
而新增長的函數式接口都在java.util.function包下。設計

Java 不會強制要求你使用 @FunctionalInterface 註解來標記你的接口是函數式接口, 然而,做爲API做者, 你可能傾向使用@FunctionalInterface指明特定的接口爲函數式接口, 這只是一個設計上的考慮, 可讓用戶很明顯的知道一個接口是函數式接口。code

入門

先來看一個入門的例子就能明白爲啥函數式接口是一種契約:對象

@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 方法同樣,只是咱們通常不會再從新定義這些方法。get

@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這個異常。hash

@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<T> 表明了一個做用於於兩個同類型操做符的操做,而且返回了操做符同類型的結果

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

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

  6. Consumer<T> 表明了接受一個輸入參數而且無返回的操做

  7. DoubleBinaryOperator 表明了做用於兩個double值操做符的操做,而且返回了一個double值的結果。

  8. DoubleConsumer 表明一個接受double值參數的操做,而且不返回結果。

  9. DoubleFunction<R> 表明接受一個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<R> 接受一個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<R> 接受一個long類型輸入參數,返回一個結果。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  43. UnaryOperator<T> 接受一個參數爲類型T,返回值類型也爲T。

本文大量參考鳥窩哥,原文請移步:https://colobu.com/2014/10/28/secrets-of-java-8-functional-interface/#@FunctionalInterface

相關文章
相關標籤/搜索