2017-10-08 61 views
3

我無法理解的差異的Java 8選配的清單收集到列表編輯錯誤

Stream<Optional<Integer>> optionalStream = Stream.of(
       Optional.of(1), 
       Optional.empty(), 
       Optional.of(5)); 

List<Optional<Integer>> optionalList = optionalStream.collect(Collectors.toList()); 

其中一期工程只是罰款之間:

List<Optional<Integer>> optionalList1 = Stream.of(
       Optional.of(1), 
       Optional.empty(), 
       Optional.of(5)).collect(Collectors.toList()); 

當我收到錯誤

Error:(138, 40) java: incompatible types: inference variable T has incompatible bounds 
    equality constraints: java.util.Optional<java.lang.Integer> 
    lower bounds: java.util.Optional<? extends java.lang.Object> 
+1

請問如果第二工作你添加一個提示,例如'Stream。<可選>(/ * etc * /'? –

+0

yes!爲什麼會發生這種情況? –

+1

好吧,你只是給類型推理算法一些更多的限制。實際上,更容易添加的會是'可選。 empty()'。感覺你不應該這樣做,但是這就是它在當前實現中的樣子。 –

回答

4

我已經減少了例子位,並試圖編譯與-XDverboseResolution=all約的類型推斷輸出信息:

final class One { 
    void one() { 
    Stream<Optional<Integer>> optionalStream = Stream.of(Optional.empty()); 
    List<Optional<Integer>> optionalList = optionalStream.collect(Collectors.toList()); 
    } 
} 

final class Two { 
    void two() { 
    List<Optional<Integer>> optionalList1 = 
     Stream.of(Optional.empty()).collect(Collectors.toList()); 
    } 
} 

Two的情況下,它看起來像的Stream.of遞延實例是連看後續collect之前完成:

... 
Two.java:9: Note: Deferred instantiation of method <T>of(T) 
     Stream.of(Optional.empty()).collect(Collectors.toList()); 
       ^
    instantiated signature: (Optional<Object>)Stream<Optional<Object>> 
    target-type: <none> 
    where T is a type-variable: 
    T extends Object declared in method <T>of(T) 
Two.java:9: Note: resolving method collect in type Stream to candidate 0 
     Stream.of(Optional.empty()).collect(Collectors.toList()); 
... 

(下稱「解決方法collectcollect首提)

沒有target-type限制它;實例化的簽名顯示它是Stream<Optional<Object>>

如果你看一下對應的輸出One

... 
One.java:8: Note: Deferred instantiation of method <T>of(T) 
    Stream<Optional<Integer>> optionalStream = Stream.of(Optional.empty()); 
                 ^
    instantiated signature: (Optional<Integer>)Stream<Optional<Integer>> 
    target-type: Stream<Optional<Integer>> 
    where T is a type-variable: 
    T extends Object declared in method <T>of(T) 
... 

它,因爲它知道目標類型得到這一權利。

對於Two,我不能準確地說出爲什麼延遲實例發生在這一點,因爲我對應用類型推斷的方式不夠熟悉。

認爲這是因爲Stream.of調用不被認爲是多晶硅的表情,但我真的不能相信自己,爲什麼(見編輯歷史有些語無倫次隨筆)。


我建議的解決方法是一種提示適用於Optional.empty(),即Optional.<Integer>empty()。這有獲得實際類型的Optional權早些時候推斷的效果,所以它在延遲實例化的時間是已知的,事件雖然目標類型仍是未知數:

final class Three { 
    void three() { 
    List<Optional<Integer>> optionalList1 = 
     Stream.of(Optional.<Integer>empty()).collect(Collectors.toList()); 
    } 
} 

... 
Three.java:9: Note: resolving method of in type Stream to candidate 1 
     Stream.of(Optional.<Integer>empty()).collect(Collectors.toList()); 
      ^
    phase: BASIC 
    with actuals: Optional<Integer> 
    with type-args: no arguments 
    candidates: 
     #0 not applicable method found: <T#1>of(T#1...) 
     (cannot infer type-variable(s) T#1 
      (argument mismatch; Optional<Integer> cannot be converted to T#1[])) 
     #1 applicable method found: <T#2>of(T#2) 
     (partially instantiated to: (Optional<Integer>)Stream<Optional<Integer>>) 
    where T#1,T#2 are type-variables: 
    T#1 extends Object declared in method <T#1>of(T#1...) 
    T#2 extends Object declared in method <T#2>of(T#2) 
Three.java:9: Note: Deferred instantiation of method <T>of(T) 
     Stream.of(Optional.<Integer>empty()).collect(Collectors.toList()); 
       ^
    instantiated signature: (Optional<Integer>)Stream<Optional<Integer>> 
    target-type: <none> 
    where T is a type-variable: 
    T extends Object declared in method <T>of(T) 
... 
3

Stream.of(...)Optional.empty()是通用方法。如果你沒有提供類型參數,它會被推斷出來。對於Optional.empty()你會得到Optional<Object>所以Stream.of(Optional.of(1), Optional.empty(), Optional.of(5))將導致Stream<Optional<? extends Object>>

您可以通過在Optional.<Integer>empty()Stream.<Optional<Integer>>of(...)中提供類型參數來解決問題。我更喜歡第一個。

+0

「對於'Optional.empty()'你會得到'可選''但你不會在第一種情況下,否則它不會工作。這個答案解決了症狀,但沒有考慮到差異。 –

+0

OP代碼中的第一種和第二種情況都包含'Optional.empty()'。如果像你所說的那樣是「可選」類型,那麼第一種情況也不起作用。 (順便說一句,我不是downvoter)。 –