關於 lambda 表達式的定義請看維基百科。html
該文章將帶你熟悉 lambda 語法,以及使用集合 API 中的 lambda 以及相關的語言加強,本文全部的代碼都是在 JDK 8 lambda build b39 編譯。java
功能接口
只包含一個方法的接口被稱爲功能接口,Lambda 表達式用用於任何功能接口適用的地方。api
java.awt.event.ActionListener
就是一個功能接口,由於它只有一個方法:void actionPerformed(ActionEvent)
. 在 Java 7 中咱們會編寫以下代碼:oracle
而 Java 8 中能夠簡化爲:
編譯器知道lambda 表達式必須符合 void actionPerformed(ActionEvent)
方法的定義。看起來 lambda 實體返回 void,實際上它能夠推斷出參數 e 的類型是 java.awt.event.ActionEvent
.ide
函數集合
Java 8 的類庫包含一個新的包 java.util.functions
,這個包中有不少新的功能接口,這些接口可與集合 API 一塊兒使用。函數
java.util.functions.Predicate
使用謂詞 (Predicate) 來篩選集合:ui
這裏咱們有兩個新方法:
java.util.functions.Block
咱們可以使用一個新的迭代器方法來替換 for 循環 void forEach(Block<? super T>)
:翻譯
forEach()
方法是
internal iteration 的一個實例:迭代過程在
Iterable
和
Block
內部進行,每次可訪問一個元素。
最後的結果就是用更少的代碼來處理集合:
這樣作的優勢是:
-
元素在須要的時候才進行計算
-
若是咱們取一個上千個元素的集合的前三條時,其餘元素就不會被映射
-
鼓勵使用方法鏈
-
咱們無需才存儲中間結果來構建新的集合
-
內部迭代過程所以大多數細節
-
例如,咱們能夠經過下面代碼來並行 map() 操做
writing
myCollection.parallel().map(e ‑> e.length())
.
方法引用
咱們可經過 :: 語法來引用某個方法。方法引用被認爲是跟 lambda 表達式同樣的,可用於功能接口所適用的地方。
咱們能夠引用一個靜態方法:
或者是一個實例的方法:
咱們也能夠建立工程方法並將構造器引用賦值給
java.util.functions.Factory
:
最後,咱們建立一個引用到隨意實例的例子:
這裏咱們無需綁定方法引用到某個實例,咱們直接將實例作爲功能接口的參數進行傳遞。
默認方法
直到今天的 Java ,都不可能爲一個接口添加方法而不會影響到已有的實現類。而 Java 8 容許你爲接口自身指定一個默認的實現:
子接口能夠覆蓋默認的方法:
或者子接口也能夠經過從新聲明一個沒有方法體的方法來刪除默認的方法:
這個將強制全部實現了 FastQueue 的類必須實現 deleteAll() 方法。
HotSpot 實現
lambda 不僅是能夠減小不少代碼的編寫,其字節碼和運行時的實現也比 Java 7 中的匿名類的效率更高。針對每個 lambda 表達式,編譯器都會建立一個對應的形如 lambda$1() 這樣的方法。這個過程被稱之爲 lambda body desugaring. 當碰見一個 lambda 表達式,編譯器將會發起一個invokedynamic
調用,並從目標功能接口中獲取返回值。
深刻閱讀
本文不少內容都基於 Brian Goetz 的文章:State of the Lambda, State of the Lambda: Libraries Edition and Translation of Lambda Expressions. 這些文字詳細描述了 lambda 語法、變量捕獲、類型接口和編譯等內容。
英文原文,OSCHINA原創翻譯
轉自:http://www.oschina.net/question/12_59047