【问题标题】:Why Stream.generate use non-variance, but Optional.orElseGet use Covariance in Java 8为什么 Stream.generate 使用非方差,而 Optional.orElseGet 在 Java 8 中使用协方差
【发布时间】:2022-01-09 11:19:42
【问题描述】:

Stream 类中的 Java 8 源代码:

public static<T> Stream<T> generate(Supplier<T> s) {
        ...
}

Optional 类中

public T orElseGet(Supplier<? extends T> other) {
    ...
}

我已经阅读了这篇文章:PECS,但我有些困惑。

为什么generate方法参数(Supplier&lt;T&gt; s)使用非方差,而orElseGet方法参数(Supplier&lt;? extends T&gt; other)使用协方差,如何决定使用协方差还是非方差

【问题讨论】:

  • 主要区别在于Optional的情况下,T已经被原来的Optional值固定了。

标签: java generics covariance


【解决方案1】:

看起来 Java 开发人员同意您的观点,即 generate 应该接受 Supplier&lt;? extends T&gt;,因为它在 Java 9 中已更改。请参阅 JDK-8132097 (Stream.generate should use a covariant Supplier as parameter)

说明

Stream.generate 的签名不使用通配符 (? 扩展),因此某些程序即使有效也会被拒绝。 签名应该是 public static Stream generate(Supplier extends T> s)。

改变是有意义的,就像做这样的事情:

Stream<CharSequence> stream = Stream.generate(new Supplier<String>() {
    @Override public String get() {
      // implementation...
    }
});

应该是完全有效的。诚然,这是一个非常人为的例子,但重点是:Supplier 应该被允许使用T 的任何子类型进行参数化。为了将其与 PECS 联系起来,Supplier 充当T 的生产者。

【讨论】:

  • 但为什么 Stream.collect &lt;R&gt; R collect(Supplier&lt;R&gt; supplier, BiConsumer&lt;R, ? super T&gt; accumulator, BiConsumer&lt;R, R&gt; combiner); 不使用 协方差
  • 我不能给出肯定的答案,因为我没有参与流的开发过程。但是,我的猜测是,这要么是疏忽,要么是他们认为没有必要;考虑到流的典型用法,不使用协方差这一事实实际上会导致问题可能很少见。但是,如果他们在任何地方都使用? extends R,则类型解析也可能存在一些模糊的问题,不确定(或者在 Java 8 中可能存在 问题,但现在作为类型可能不再是问题随着时间的推移,推理得到了改进)。
  • 推测为什么它没有与generate一起更改,可能只是没有人为collect提交错误报告。虽然generate 是一个静态方法,因此不能被覆盖,但它可能更容易更改而不破坏向后兼容性。
  • 谢谢!这对我很有帮助。 Stream.collect()Java17 中仍然保持 non-variance。我不知道为什么。
猜你喜欢
  • 2015-11-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-09
  • 2014-12-14
相关资源
最近更新 更多