繁体   English   中英

为什么这段代码只用一个冗余的 map() 编译?

[英]Why does this code only compile with a redundant map()?

我遇到了一个我无法解释的怪事。

以下代码(一个最小示例)将无法编译:

class Test {
  interface I {}

  Optional<I> findOne(ArrayList<? extends I> list) {
    return list.stream()
        .findFirst();
  }
}

javac(至少版本 11)说:

error: incompatible types: Optional<CAP#1> cannot be converted to Optional<I>
        .findFirst();
                  ^
  where CAP#1 is a fresh type-variable:
    CAP#1 extends I from capture of ? extends I

但是,我随机发现,将看似冗余的.map() 调用添加到 ZF7B44CFFAFD5C52223D5498196C8A2E7BZ [编辑:它实际上已添加到由 findFirst()] 返回的 Optional 中编译得很好:

class Test {
  interface I {}

  Optional<I> findOne(ArrayList<? extends I> list) {
    return list.stream()
        .findFirst()
        .map(a -> a);
  }
}

我很好奇那里发生了什么,添加 .map() 调用让它编译。

[我知道将方法参数更改为采用ArrayList<I>是可行的,但这不是我要问的。]

Generics 是不变的

第一个无法编译,因为 Java generics 是不变的。

Optional<Dog>Optional<Animal>完全不同,因此Optional<...> with ...是 your ? 捕获的与Optional<I>不兼容。

为了详细说明,请考虑以下示例:

List<Dog> dogs = new ArrayList<>();

List<Animal> animals = dogs; // this does not compile, but pretend it would
animals.add(new Cat());

Dog dog = dogs.get(0); // should be safe, but its actually a cat!

向上转型

但是使用map(a -> a)你有一个类型的隐式向上转换,比如(Animal) dog这使得它实际上是一个Optional<Animal> 因此,在您的情况下, Optional<I>而不是Optional<...>

所以你a -> a lambda,它看起来很无辜,实际上是一种获取Dog (或...?在你的情况下)并发出Animal (或I )的方法:

a -> (I) a

考虑以下示例

Optional<Dog> dog = Optional.of(new Dog());

Optional<Animal> animal = dog.map(d -> d);

这正好说明了你的情况。 由于不变性,您不能只分配它,您必须主动转换它。 并且由于上下文, Java 可以将d隐式转换为Animal 所以代码相当于

dog.map(d -> (Animal) d);

笔记

请注意,您在此处调用的map方法不是来自mapStream而是来自Optional的 map ,这是findFirst的结果。 因此,其目的是通过应用给定的转换,将 map 从Optional<X>Optional<Y>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM