2014-01-21 39 views
5

說,我有一個方法:爲什麼Java的類型推斷如此薄弱?

public static <T> Collection<T> addToCollection(T element, Collection<T> collection) { 
    collection.add(element); 
    return collection; 
} 
試圖編譯這段代碼時

然後:

Integer i = 42; 
Collection<Integer> result = addToCollection(i, Collections.emptyList()); 

我得到一個錯誤Type mismatch: cannot convert from Collection<Object> to Collection<Integer>。 任何人都可以解釋爲什麼類型系統不能推斷Collections.emptyList()應該是Collection<Integer>類型?

上面的例子顯然很人造,但我總是偶然發現了這個限制,這真的很煩人。在閱讀之後有效的Java我發現你可以簡單地做Collections.<Integer>emptyList()(必須說,這對我來說當時是一個啓示)並且一切編譯都很順利,但是當你有一些複雜的類型時,它確實是一個滋擾。

我只是想知道這是否是某種錯誤,或者是否有任何有效的理由使它以這種方式工作?

+9

請您重溫一下這個標題嗎? – Kobi

+3

談一下把水壺調黑的方法。 Collections.emptyList()返回一個不可修改的List,所以代碼無法工作。 – Kayaman

+3

@Kayaman旁邊的點,因爲OP表示自己。問題是關於推理的原則,運行時沒有考慮到它。 –

回答

11

在Java 8中對類型推斷系統進行了改進,引入了target typing,以便爲流和lambdas提供更多的表現力。因此,您的代碼將與Java 8一起編譯。

關於它的更多信息,請參閱updated tutorial,頁面底部有一個非常類似的示例。

+0

TIL!這真棒 - 我在這些情況下在javac自己嘟u過難聽的單詞。我將不得不明天嘗試一下(在這臺機器上沒有jdk 8)。如果我也希望這個更好的推論與三元論一起工作,我會感到失望嗎? '列表 foo = myBool? someList:Collections.emptyList()' – yshavit

+1

@yshavit也編譯。 – assylias

+1

很多年前,在史詩BGGA/CICE/FCM戰鬥時,我讀到[某處](https://weblogs.java.net/blog/carcassi/archive/2010/04/09/two-problems-泛型-java-0):「Java應該專注於修復它的泛型,而不是引入另一層複雜性」。原來他們做了前者作爲後者的服務:) –

0

Collections.emptyList()返回一個List<Object>這是通過您的addToCollection()方法。由於Object不是整數,所以失敗。

+0

這是不正確的。這是一種通用的方法。 –

+0

' public static List emptyList()'---作爲圍繞常量「EMPTY_LIST」的方法包裝引入,只是出於這個原因。 –

+0

這是一個通用的方法,但有兩種選擇在何處綁定泛型:根據參數或基於返回類型。在這裏,顯然綁定是基於你傳入的第二個參數發生的。 – rec

0

這樣做有什麼害處?

Integer i = 42; 
List<Integer> emptyList = Collections.emptyList(); 
Collection<Integer> result = addToCollection(i, emptyList); 

在java 8中它將被照顧。