Java開發人員應該對java.lang.Runnable,java.util.Comparator,java.util.concurrent.Callable 等等接口不會感到陌生。他們都只有一個單一的抽象方法。這樣的接口,我們通常叫單一抽象方法接口(SAM,Single Abstract Method Interface)。
以前大家應該經常使用下面的代碼片段
public class InnerAnonymousClassSample { public static void main(String[] args){ new Thread(new Runnable() { @Override public void run() { System.out.println("Anonymous Class Thread Demo"); } }).start(); }}
在Java 8 中,對於這種擁有單一抽象方法的接口,換了個名字,叫函數接口。所以,這個不是什麼新東西,這個名字也是為了Lambada表達式而生。還是拿Runnable來說事,看看和Lambda表達式合壁後的結果。
public class ThreadWithLambda { public static void main(String[] args){ new Thread(() -> System.out.println("Thread with Lambda expression Demo")).start(); } }
回到函數接口上來,Java引入了@FunctionalInterface注解。用了它,你定義的接口就得是只有一個抽象方法的函數接口,否則會報編譯錯誤。
@FunctionalInterface public interface FunInterfaceAnnotationDemo { public void absMethodDemo(); public void absMoreMethodDemo(); }
Error:(8, 1) java: 意外的 @FunctionalInterface 注釋 com.tr.learning.lambda.FunInterface.FunInterfaceAnnotationDemo 不是函數接口 在 接口 com.tr.learning.lambda.FunInterface.FunInterfaceAnnotationDemo 中找到多個非覆蓋抽象方法
上述方法可以通過Java 8中引入的關鍵字default 在接口中為其中一個抽象方法指定一個默認實現,這樣上述接口就會變成合法的函數接口了。
@FunctionalInterface public interface FunInterfaceAnnotationDemo { public void absMethodDemo(); default public void absMoreMethodDemo(){ System.out.println("Default implementation of method ininterface"); }
一旦有了default 關鍵字,現在的接口就好像變成了抽象類。這讓人總覺得怪怪的。這個default的接口主要是為了向後兼容。當你往一個擁有眾多子類的接口中添加方法時,你總不想一個子類一個子類的去把方法實現吧?這在Java JDK不斷升級的過程中,是一個很現實的問題。至於說使用帶default實現的接口還是抽象類,我認為在進行Java代碼的設計時,還是抽象類更合適。