lambda表達式:
為什么要使用lambda表達式?
- 避免匿名內部類定義過多
- 可以讓代碼看起來簡潔
- 去掉了一堆沒有意義的代碼,只留下核心的邏輯
Functional Interface(函數式接口)
- 任何接口,如果只包含唯一一個抽象方法,那么它就是一個函數式接口
- 對於函數式接口,可以通過lambda表達式來創建該接口的對象
函數式接口的推導
首先定義一個函數式接口
若要實現這個接口,正常情況下我們需要寫一個接口實現類,然后通過new這個類的對象來調用其中的方法:
為了調用接口中的方法,需要單獨定義一個接口的實現類,不是很方便,於是在我們在同一個類中定義靜態內部類:
可以看到,MyClass2定義在方法外面,依然有些繁瑣,於是我們開始使用局部內部類:
為了進一步簡化,我們還可以使用匿名內部類:
演化到這里,代碼已經很精簡了,但是依然有繁瑣的代碼導致核心代碼依然不突出,為了進一步簡化,只突出核心代碼,我們使用了lambda來簡化:
接口 = (參數列表) -> {
代碼;
};
其中,參數列表依據函數式接口中的方法參數而定,可以沒有,也可以有多個
lambda表達式使代碼達到了最簡,只保留了接口名,參數和執行體
到此,我們清楚了lambda表達式的由來,最終的效果是我們定義一個函數式接口,通過一句lambda表達式就能調用里面的方法。lambda表達式使代碼達到了最精簡,只突出核心語句,去掉了沒有意義的代碼。
不知大家是否發現,文章最開頭給出的代碼是帶new關鍵字的,我們用自己寫的函數式接口不能用lambda函數作為參數把對象new出來,不知大家是否陷入了疑惑。別忘了,接口是不能被實例化的!如果一個接口能被實例化,只能說明他不是一個接口,而是一個類!
事實上,文章開頭給出的lambda表達式
是一個匿名內部類,Thread並不是函數式接口,而是函數式接口Runnable的實現類,因為接口是不能被實例化的,若Thread是函數式接口則不能使用new關鍵字創建對象。根據上述推理lambda的過程向上倒推,我們會發現實際上上述語句等價於:
通過查看Java源碼可以看到,Thread類中存在接收一個參數的構造方法,而start()方法調用了start0()方法,start0()又調用了run()方法,因此上述代碼又相當於:
實際測試運行結果也確實相同,到這里我們不難看出,這就是一個實現了一個接口並重寫接口中方法的匿名內部類。
那么新問題又來了,為什么說lambda表達式只支持函數式接口,是不是意味着函數式接口和實現了函數式接口的類都能用lambda表達式?事實上,lambda表達式作為參數值時,只需要形參類型為函數式接口即可,與類是否實現函數式接口無關。
當然,該段代碼純屬為了搞清楚語法規則,並沒有實際意義。因此,lambda表達式只支持函數式接口(只有一個抽象方法的接口)是因為lambda表達式作為參數時,只能用函數式接口作為形參來接收。
本人僅僅是因為對Java中的lambda感興趣進行研究后的記錄,把結果記錄並分享出來,如果對大家有任何幫助我感到萬分榮幸,因個人水平有限,文章中可能存在錯誤或者不正確的觀點,歡迎大家批評指出。