java 8 可选列表收集以列出编译错误

Kon*_*ewa 4 java java-8

我无法理解之间的区别

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

List<Optional<Integer>> optionalList = optionalStream.collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

效果很好并且:

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

我在哪里收到错误

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>
Run Code Online (Sandbox Code Playgroud)

lex*_*ore 5

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(...)。我更喜欢第一个。


And*_*ner 5

我稍微减少了示例,并尝试编译 with-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());
  }
}
Run Code Online (Sandbox Code Playgroud)

在 的情况下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());
...
Run Code Online (Sandbox Code Playgroud)

(“解决方法collect是第一次提到的collect”)

没有什么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)
...
Run Code Online (Sandbox Code Playgroud)

它之所以能做到这一点是因为它知道目标类型。

我无法确切地说为什么此时会发生延迟实例化Two,因为我对类型推断的应用方式不够熟悉。

认为这是因为 的调用Stream.of不被认为是多重表达式,但我无法真正说服自己为什么(请参阅编辑历史以了解一些不连贯的胡言乱语)。


我建议的修复方法是将类型提示应用于Optional.empty(), ie 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)
...
Run Code Online (Sandbox Code Playgroud)