java - 为什么此代码仅使用冗余 map() 进行编译?

标签 java generics

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

以下代码(最小示例)不会编译:

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() 调用 [edit:它实际上被添加到 findFirst() 返回的 Optional 中] 编译得很好:

class Test {
  interface I {}

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

我很好奇那里发生了什么,添加 .map() 调用可以让它编译。<​​/p>

[我知道更改方法参数以获取 ArrayList<I>有效,但这不是我要问的。]

最佳答案

泛型是不变的

第一个无法编译,因为 Java 泛型是不变的

Optional<Dog>Optional<Animal> 完全不同,因此 Optional<...>...成为你的类型 ?捕获与 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 ,这是 findFirst 的结果.所以它的目的是从 Optional<X> 映射到Optional<Y>通过应用给定的转换。

关于java - 为什么此代码仅使用冗余 map() 进行编译?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61781355/

相关文章:

java - Android - 如何将 bundle 从一个应用程序发送到另一个应用程序?

templates - 如何在 Rust 中使用数值作为泛型参数?

java - 如何告诉Java两个通配符类型相同?

c# - 通用的、编译时安全的延迟加载方法的方法

java - 如何使用 JSP/Java 检测移动设备(iOS 和 Android)?

java - Excel 无法以正确的格式导出

java - C# 通用通配符

c# - 如何使用我的 List<Type> 中的类型?

java - 在 Java 中将排序数组重写为 JTextPane

java - 静态字符串中的非固定宽度文本 - Jasper Reports