[英]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>
是可行的,但这不是我要问的。]
第一个无法编译,因为 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
方法不是来自map
的Stream
而是来自Optional
的 map ,这是findFirst
的结果。 因此,其目的是通过应用给定的转换,将 map 从Optional<X>
到Optional<Y>
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.