函數式接口(Functional Interface)就是一個有且僅有一個抽象方法,但是可以有多個非抽象方法的接口。
函數式接口可以被隱式轉換為 lambda 表達式。
JDK 1.8 新增加的函數接口,
舉例之前先看下函數式接口簡介,所以函數式接口到底什么意思呢?我們先拋開分支只講重點,其實函數式接口指的就是只有一個抽象方法的接口,那么這類接口單獨拎出來給了一個名字,就叫函數式接口。
所以這類接口以前就存在,只不過沒有歸類取名字,比如Runnable接口等。
為此java8這次為這類接口引入了一個新的注解@FunctionalInterface,主要用于編譯級錯誤檢查,加上該注解,當你寫的接口不符合函數式接口定義的時候,編譯器會報錯,比如像以前就有的Runnable接口,可以進源碼看看,可以發現已經補上了@FunctionalInterface。
接下來問題是,為什么這類接口要單獨拎出來講,這是因為java在函數式編程這塊有缺陷,方法不能作為參數傳遞,只能依靠類進行曲線救國,這次的函數式接口就是為了彌補這塊的不足,從命名也能看出目的。而之前有講到的lambda也不是java獨有的,其它支持函數式編程的語言早就支持lambda表達式,那么lambda表達式在java中該怎么理解,和函數式接口又是什么關系呢?接下來我們舉個??看看
import org.junit.Test; import java.util.function.Function; /** * @author lc * @describe 功能描述 * @Date 10:54 on 2019/8/11 */ public class Java8 { public static void main(String[] args) { } @Test public void testFun(){ String testStr = "abcd"; //java8之前的寫法 StrSubitFun fun1 = new StrSubitFun() { @Override public String subString(String inStr,int startIndex) { return inStr.substring(startIndex); } }; //java8lambda StrSubitFun funLambda = (String inStr, int startindex) -> inStr.substring(startindex); //java8 方法引用 StrSubitFun funReference = String::substring; System.out.println(fun1.subString(testStr,1)); System.out.println(funLambda.subString(testStr,1)); System.out.println(funReference.subString(testStr,1)); } /** * 字符串分割接口 */ interface StrSubitFun{ String subString(String inStr,int startIndex); } }
接下來再看看我們的問題:lambda表達式在java中該怎么理解,和函數式接口又是什么關系呢?
//java8lambda StrSubitFun funLambda = (String inStr, int startindex) -> inStr.substring(startindex);
從這行代碼可以明顯看出,lambda表達式返回值是一個實例,并且這個實例的類型是之前說過的函數式接口。
也就是說lambda其實就是這個函數式接口的實現(可以理解成new),最開始我們就知道函數式接口的特點,就是只有一個抽象方法,那么這里隱含了lambda表達式所實現的內容其實就是這一個抽象方法(可以理解成實現了這個抽象方法)。
所以綜上所述,lambda表達式其實隱含了2步,實例化函數式接口,并實現了唯一的一個抽象方法。(這個只是理解,實際上還是有差異,比如內存結構等)
也就可以看出,java8彌補了函數式編程的缺乏,同時仍然是曲線救國,依然不能把方法當參數,但是在編碼過程中通過lambda同樣達到函數式編程的寫法和效果。
最后做一個總結:
1、如果一個接口只有一個抽象方法,那么該接口就是一個函數式接口。
2、如果我們在某個接口上聲明了FunctionalInterface注解,那么編譯器就會按照函數式接口的定義來要求該接口。
3、如果某個接口只有一個抽象方法,但我們并沒有給該接口聲明FuncationalInterface注解,那么編譯器依舊依舊會將該接口看作是函數式接口。(雖這樣說,但是一般對于函數式接口建議還是加上這個注解的比較好。因為加了之后編譯器會對接口增加一個強制性的保證,如果接口不滿足某些條件的話是會報錯提示的,就這好比子類重寫父類的一個特定方法的時候,照理是應該在子類的這個方法上增加一個override方法,但是如果不加也沒問題,加了的好處一是代碼可讀性比較好,二是如果覆寫了父類中并不存在的方法那么編譯器會第一時間提示出來,所以最好按照規則來:如果滿足函數式接口一定要在接口上聲明FuncationalInterface注解)