我稍微减少了示例,并尝试编译-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());
...
(“解决方法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)
...
它之所以能做到这一点是因为它知道目标类型。
我无法确切地说为什么此时会发生延迟实例化Two
,因为我对类型推断的应用方式不够熟悉。
I think这是因为调用Stream.of
不被认为是多重表达式,但我无法真正说服自己为什么(请参阅编辑历史以了解一些不连贯的杂文)。
我建议的修复是将类型提示应用于Optional.empty()
, i.e. 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)
...