標籤:exp lint index tor 抽象方法 tutorial lang 結果 體系
本篇文章不介紹Lambda的前世今生,這裡只對Lambda表達的應用做詳細瞭解。以及與內部類的差異點。
Lambda運算式
Lambda運算式是Java SE 8版本中引入的新的文法糖。將功能看做方法參數,將代碼看做資料。
Lambda運算式文法:
LambdaParameters -> LambdaBody
Lambda運算式分為三部分:
如:
() -> {} // 無參,返回結果為空白(x) -> System.out.println(x); // 帶有一個參數(Thread t) -> { t.start(); } // 帶有一個申明參數(int x, int y) -> x + y; // 帶有兩個申明參數,一個方法參數;(int x, int y) -> return x +y; // 帶有兩個申明參數,一個方法參數;(x, y) -> return x +y; // 帶有兩個申明參數,一個方法參數;
總體上表現如上形式,是Java中一種新的風格的運算式,和普通的表達的確有很大風格上的差異性。
這種風格的文法優勢:
函數式介面
已經對lambda運算式定義好了,但是如何在相容物件導向的Java體系中使用。在物件導向體系中,一切皆是對象,怎樣將這種運算式作為對象去使用,從而引入函數使介面:只有一個抽象方法的介面,代表著單功能的契約。
為了區分函數式介面和只包含一個抽象方法的普通介面,需要使用@FunctionalInterface註解標註介面,這樣編譯器就能將其作為函數式介面處理。
有了函數式介面就可以很方便的使用lambda運算式,使用Java來進行函數式編程。
Function<String, String> f = (String x) -> x.toUpperCase();f.apply("msg");
lambda運算式可以賦值給函數式介面,這裡涉及到目標類型上下文,編譯器根據lambda運算式所在的上下文推導其目標類型為Function。
List<String> list = new ArrayList<>();list.forEach((x) -> System.out.println(x));
lambda運算式作為方法參數,其實是list.forEach方法中的方法參數是函數式介面,編譯器推導lambda運算式類型為forEach中的函數式介面類型作為lambda運算式的目標類型。
從以上可以看出:
lambda運算式的目標類型必須是函數式介面,但是函數式介面和lambda運算式是兩部分,函數式介面並不屬於lambda運算式一部分,只是作為其目標類型;
函數式介面的抽象方法參數必須與lambda運算式的相一致:數量和個數;
函數式介面抽象方法返回參數與lambda運算式傳回值一致:類型;
lambda運算式中拋出的受檢異常與函數式介面抽象方法上的throws保持一致;
函數式介面使得lambda運算式能夠更好的使用。Java是物件導向,如果在此基礎上引入lambda,勢必需要向前相容:
如果使用已有的介面表示:
基於這些原因,選擇已有的介面類型作為函數式介面,然後引入lambda運算式是最折中平衡的方式。
Lambda運算式與匿名內部類
lambda運算式的簡潔、緊湊的文法結構是匿名內部類所不能比擬的;
lambda運算式具有更明確的語義——因為只關注有效代碼;
lambda運算式的範圍比匿名內部類更加有友好(詞法範圍/新的內部範圍):this在lambda運算式中表示外部內,而在內部類中表示當前內部類執行個體;變數名在lambda運算式中就是表示外部的,而在內部類中要防止繼承自超類———lambda的詞法範圍;(shadow問題)
lambda是函數式編程的體現,內部類任然是在物件導向層面;
參考
深入理解Java 8 Lambda(語言篇——lambda,方法引用,目標類型和預設方法)
The Java? Language Specification
Lambda Expressions
Java 8——Lambda運算式