[英]Why does this code only compile with a redundant map()?
I've come across an oddity I can't explain.我遇到了一个我无法解释的怪事。
The following code (a minimal example) won't compile:以下代码(一个最小示例)将无法编译:
class Test {
interface I {}
Optional<I> findOne(ArrayList<? extends I> list) {
return list.stream()
.findFirst();
}
}
javac (version 11 at least) says: 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
However, I sort of randomly found that adding a seemingly redundant.map() call to the stream [ edit : it's actually added to the Optional returned by findFirst()] compiles fine:但是,我随机发现,将看似冗余的.map() 调用添加到 ZF7B44CFFAFD5C52223D5498196C8A2E7BZ [编辑:它实际上已添加到由 findFirst()] 返回的 Optional 中编译得很好:
class Test {
interface I {}
Optional<I> findOne(ArrayList<? extends I> list) {
return list.stream()
.findFirst()
.map(a -> a);
}
}
I'm curious about what is happening there that adding the.map() call lets it compile.我很好奇那里发生了什么,添加 .map() 调用让它编译。
[I know that changing the method parameter to take an ArrayList<I>
works, but that's not what I'm asking about.] [我知道将方法参数更改为采用
ArrayList<I>
是可行的,但这不是我要问的。]
The first does not compile because Java generics are invariant .第一个无法编译,因为 Java generics 是不变的。
An Optional<Dog>
is completely different to an Optional<Animal>
, hence Optional<...>
with ...
being the type your ?
Optional<Dog>
与Optional<Animal>
完全不同,因此Optional<...>
with ...
是 your ?
captured is not compatible to Optional<I>
.捕获的与
Optional<I>
不兼容。
To elaborate, consider the following example:为了详细说明,请考虑以下示例:
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!
But with the map(a -> a)
you have an implicit upcast of the type, like (Animal) dog
which makes this actually an Optional<Animal>
.但是使用
map(a -> a)
你有一个类型的隐式向上转换,比如(Animal) dog
这使得它实际上是一个Optional<Animal>
。 So Optional<I>
instead of Optional<...>
in your case.因此,在您的情况下,
Optional<I>
而不是Optional<...>
。
So your a -> a
lambda, which looks innocent actually is a method taking Dog
(or ...
from ?
in your case) and giving out an Animal
(or I
):所以你
a -> a
lambda,它看起来很无辜,实际上是一种获取Dog
(或...
从?
在你的情况下)并发出Animal
(或I
)的方法:
a -> (I) a
Consider the following example考虑以下示例
Optional<Dog> dog = Optional.of(new Dog());
Optional<Animal> animal = dog.map(d -> d);
which demonstrates exactly your situation.这正好说明了你的情况。 Because of invariance you can not just assign it, you have to actively convert it.
由于不变性,您不能只分配它,您必须主动转换它。 And because of context, Java can implicitly cast the
d
to Animal
.并且由于上下文, Java 可以将
d
隐式转换为Animal
。 So the code is equivalent to所以代码相当于
dog.map(d -> (Animal) d);
Note that the map
method you call here is not the map
from Stream
but from Optional
, which is the result of findFirst
.请注意,您在此处调用的
map
方法不是来自map
的Stream
而是来自Optional
的 map ,这是findFirst
的结果。 So its purpuse is to map from an Optional<X>
to an Optional<Y>
by applying the given transformation.因此,其目的是通过应用给定的转换,将 map 从
Optional<X>
到Optional<Y>
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.