2017-10-08 22 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)。 –