以下类和方法:
class A<T extends B> { }
class B {}
Stream<A<? extends B>> find() {
return findAll() // Stream<Optional<A<? extends B>>>
.filter(Optional::isPresent) // Stream<Optional<A<? extends B>>>
.map(Optional::get) // Stream<A<capture of ? extends B>>
.filter(a -> false); // Stream<A<capture of ? extends B>>
}
Stream<Optional<A<? extends B>>> findAll() {
return Stream.empty();
}
使用javac可以正常编译,但是会导致IDEA中出现类型错误:
当我选择时,错误消失
filter(Optional::isPresent()).map(Optional::get)
对filter
通话我对此毫无意义。这是一个IDEA错误吗?
编辑: 感谢LuCio提供了一些新见解:
虽然我的javac(10.0.2)版本没有抱怨,其他javac版本和IDE都有抱怨,所以这不是IDEA错误
将表达式拆分为两个并为中间值指定显式类型会有所帮助:
Stream<A<? extends B>> aStream = findAll()
.filter(Optional::isPresent)
.map(Optional::get);
return aStream
.filter(a -> false);
(请注意,尽管IDEA推断aStream
的类型是Stream<? extends A<? extends B>>
,尽管它只接受对此类型的赋值)
问题就变成了:为什么中间类型是它的原样,为什么通过分配给另一个类型而忽略它显然是可以的?
答案 0 :(得分:2)
这是因为Stream.map
具有以下签名:
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
在这种情况下,R
是A<? extends B>
。因此,该函数的返回值是隐式的
? extends A<? extends B>
在这一点上,我相信这个问题在一定程度上得到了
的回答Is List<Dog> a subclass of List<Animal>? Why are Java generics not implicitly polymorphic?
可以通过更改返回类型来使其很好地编译:
<T extends B> Stream<? extends A<? extends B>> find() {
return findAll() // Stream<Optional<A<? extends B>>>
.map(Optional::get) // Stream<A<capture of ? extends B>>
.filter(a -> false); // Stream<A<capture of ? extends B>>
}
或显式强制转换函数以返回A<? extends B>
:
<T extends B> Stream<A<? extends B>> find() {
return findAll()
.map((Function<Optional<A<? extends B>>, A<? extends B>>) Optional::get)
.filter(a -> false);
}
需要说明的是,Stream<C>
本身不是C extends A<B>
的地方Stream<A<? extends B>>
。