鮮為人知的Java8特性:泛化目標類型推斷

jopen 10年前發布 | 19K 次閱讀 Java8 Java開發

在瀏覽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

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!