函數時接口@FunctionalInterface


轉自:https://www.xttblog.com/?p=3453

函數式接口(Functional Interface)

函數式接口(Functional Interface)是 Java 8對一類特殊類型的接口的稱呼。 這類接口只定義了唯一的抽象方法的接口(除了隱含的Object對象的公共方法), 因此最開始也就做SAM類型的接口(Single Abstract Method)。

說白了,所謂的函數式接口,當然首先是一個接口,然后就是在這個接口里面只能有一個非 Object 對象的公共方法的抽象方法,可以有多個靜態方法和默認方法。

上面說的是概念,如果你還沒看懂,沒關系,我們繼續通過下面的幾個例子,我相信你就會明白。

JDK 8之前已有的函數式接口

JDK 8之前已有的 JDK 中提供的支持函數式編程的函數式接口。

  • java.lang.Runnable
  • java.util.concurrent.Callable
  • java.security.PrivilegedAction
  • java.util.Comparator
  • java.io.FileFilter
  • java.nio.file.PathMatcher
  • java.lang.reflect.InvocationHandler
  • java.beans.PropertyChangeListener
  • java.awt.event.ActionListener
  • javax.swing.event.ChangeListener

Java8 中新定義的函數式接口

Java8 中有一個 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

下面我們來看一個案例。

1 @FunctionalInterface
2 public interface XttblogService {
3     void sayMessage(String message);
4 }
 

那么我們現在就可以使用 Lambda 表達式來表示該接口的一個實現(注:JAVA 8 之前一般是用匿名類實現的):

   XttblogService xttblogService = message -> System.out.println("Hello " + message);

@FunctionalInterface 注解的接口,只能有一個 public 接口。

如果定義了兩個,就會報錯。

但是我們可以定義多個默認方法。因為默認方法不是抽象方法,其有一個默認實現,所以是符合函數式接口的定義的。

除此之外,我們還可以定義多個靜態方法。
 
 

函數式接口里允許定義默認方法和靜態方法,上面的兩種寫法都不會報錯。

另外,函數式接口里還允許定義 java.lang.Object 里的 public 方法。

函數式接口里是可以包含 Object 里的 public 方法,這些方法對於函數式接口來說,不被當成是抽象方法(雖然它們是抽象方法);因為任何一個函數式接口的實現,默認都繼承了 Object 類,包含了來自 java.lang.Object 里對這些抽象方法的實現。

 

我們常用的一些接口 Callable、Runnable、Comparator 等在 JDK8 中都添加了 @FunctionalInterface 注解。

那么 Java 中為什么需要 @FunctionalInterface 注解呢?

沒有這個注解,我們也可以實現 Lambda 表達式。

但是 Java 推出 @FunctionalInterface 注解的原因是在 Java Lambda 的實現中,開發組不想再為 Lambda 表達式單獨定義一種特殊的 Structural 函數類型,稱之為箭頭類型(arrow type),依然想采用 Java 既有的類型系統(class, interface, method等)。增加一個結構化的函數類型會增加函數類型的復雜性,破壞既有的 Java 類型,並對成千上萬的 Java 類庫造成嚴重的影響。權衡利弊,因此最終還是利用 SAM 接口作為 Lambda 表達式的目標類型。

JDK 中已有的一些接口本身就是函數式接口,如 Runnable。JDK 8 中又增加了 java.util.function 包,提供了常用的函數式接口。

 

函數式接口代表的一種契約,一種對某個特定函數類型的契約。在它出現的地方,實際期望一個符合契約要求的函數。Lambda 表達式不能脫離上下文而存在,它必須要有一個明確的目標類型,而這個目標類型就是某個函數式接口。


免責聲明!

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



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