其實之前在講Lambda表達式的時候提到過,所謂的函數式接口,當然首先是一個接口,然後就是在這個接口裡面只能有一個抽象方法。
這種類型的接口也稱為SAM接口,即Single Abstract Method interfaces。
它們主要用在Lambda表達式和方法引用(實際上也可認為是Lambda表達式)上。
如定義了一個函數式接口如下:
@FunctionalInterface interface GreetingService { void sayMessage(String message); }
那麼就可以使用Lambda表達式來表示該接口的一個實現(注:JAVA 8 之前一般是用匿名類實現的):
GreetingService greetService1 = message -> System.out.println("Hello " + message);
Java 8為函數式接口引入了一個新注解@FunctionalInterface,主要用於編譯級錯誤檢查,加上該注解,當你寫的接口不符合函數式接口定義的時候,編譯器會報錯。
正確例子,沒有報錯:
@FunctionalInterface interface GreetingService { void sayMessage(String message); }
錯誤例子,接口中包含了兩個抽象方法,違反了函數式接口的定義,Eclipse報錯提示其不是函數式接口。
提醒:加不加@FunctionalInterface對於接口是不是函數式接口沒有影響,該注解知識提醒編譯器去檢查該接口是否僅包含一個抽象方法
函數式接口裡是可以包含默認方法,因為默認方法不是抽象方法,其有一個默認實現,所以是符合函數式接口的定義的;
如下代碼不會報錯:
@FunctionalInterface interface GreetingService { void sayMessage(String message); default void doSomeMoreWork1() { // Method body } default void doSomeMoreWork2() { // Method body } }
函數式接口裡是可以包含靜態方法,因為靜態方法不能是抽象方法,是一個已經實現了的方法,所以是符合函數式接口的定義的;
如下代碼不會報錯:
@FunctionalInterface interface GreetingService { void sayMessage(String message); static void printHello(){ System.out.println("Hello"); } }
函數式接口裡是可以包含Object裡的public方法,這些方法對於函數式接口來說,不被當成是抽象方法(雖然它們是抽象方法);因為任何一個函數式接口的實現,默認都繼承了Object類,包含了來自java.lang.Object裡對這些抽象方法的實現;
如下代碼不會報錯:
@FunctionalInterface interface GreetingService { void sayMessage(String message); @Override boolean equals(Object obj); }
java.lang.Runnable,
java.awt.event.ActionListener,
java.util.Comparator,
java.util.concurrent.Callable
java.util.function包下的接口,如Consumer、Predicate、Supplier等