鮮為人知的Java8特性:泛化目標類型推斷
在瀏覽Java8的特性列表的時候,目標類型推斷這個特別有趣的、鮮為人知的特性一下子吸引了我。Java語言的設計者通過它讓我們減輕了一些使用泛型時(Java5-7)的痛苦。讓我們來看看過去泛型使用的示例:
class List<E> { static <Z> List<Z> nil() {..} static <Z> List<Z> cons(Z head, List<Z> tail) {..} E head() {..} }
在上述例子,在JEP:101中聲稱可以用下面的方法更好地表示:
// 建議寫法: List.cons(42, List.nil()); String s = List.nil().head(); // 不推薦的寫法: List.cons(42, List.<Integer>nil()); String s = List.<String>nil().head();
作為一個熟練的API設計師,在Java路線圖中看到示例中的進步著實令人激動。這些令人興奮的變化究竟包含了什么?讓我來更加詳細地說明:
// 通過賦值語句推斷泛型的類型 List<String> l = List.nil(); // 更好的辦法是讓編譯器從函數的參數類型中直接推斷 List.cons(42, List.nil()); // 或者從“鏈式調用”中推斷 String s = List.nil().head();
因此在上面的鏈式方法調用中,會延遲到整個賦值表達式完成時才進行類型推斷。通過賦值語句左邊,編譯器會為head()
調用推斷;為
String
。然后,再次推斷nil()
調用的為
String
。 在我看來這真的很神奇。 對nil()
方法的AST計算會延遲到“關聯”子節點計算時才最后完成。這是一個很棒的主意,不是嗎?
是的,確實很棒!
你可能也會這么認為。因為一組流暢的API,像 jooq 或 Stream API在設計時會考慮到這種調用的流暢性,在鏈式調用的最后才進行類型推斷。為此,我下載了最新的JDK 8評估版本測試下面的程序:
public class InferenceTest { public static void main(String[] args) { List<String> ls = List.nil(); List.cons(42, List.nil()); String s = List.nil().head(); } }
以下是得到的編譯結果:
C:\Users\Lukas\java8>javac InferenceTest.java InferenceTest.java:5: error: incompatible types: Object cannot be converted to String String s = List.nil().head(); ^ 1 error
從結果中可以看到,基于該方法參數的類型推斷已經實現了(因此編譯通過了),但是鏈式方法調用中的類型推斷還沒有實現。我在網上搜索到了一個解釋,從Stack OverFlow 問題鏈接到lambda-dev開發者郵件列表中。
看來,Java類型系統已經變得相當復雜。由于太過復雜,要實現這種瘋狂的類型推斷變得不太現實。但是,每天編寫Java 8代碼的時候,即使略有改善也有重大的價值。
最后,希望在Java 9中會有 val
和 var 這樣的關鍵字,與其他語言一樣。
原文鏈接: javacodegeeks 翻譯: ImportNew.com - 彭秦進
譯文鏈接: http://www.importnew.com/8301.html