泛型类型上的流操作链导致类型错误

时间:2018-10-21 15:22:16

标签: java generics

以下类和方法:

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中出现类型错误: screenshot

当我选择时,错误消失

  • 删除filter(Optional::isPresent()).map(Optional::get)
  • 删除最终的filter通话

我对此毫无意义。这是一个IDEA错误吗?

编辑: 感谢LuCio提供了一些新见解:

  1. 虽然我的javac(10.0.2)版本没有抱怨,其他javac版本和IDE都有抱怨,所以这不是IDEA错误

  2. 将表达式拆分为两个并为中间值指定显式类型会有所帮助:

    Stream<A<? extends B>> aStream = findAll()
            .filter(Optional::isPresent)
            .map(Optional::get);
    return aStream
            .filter(a -> false);
    

    (请注意,尽管IDEA推断aStream的类型是Stream<? extends A<? extends B>>,尽管它只接受对此类型的赋值)

问题就变成了:为什么中间类型是它的原样,为什么通过分配给另一个类型而忽略它显然是可以的?

1 个答案:

答案 0 :(得分:2)

这是因为Stream.map具有以下签名:

<R> Stream<R> map(Function<? super T, ? extends R> mapper);

在这种情况下,RA<? 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>>