理解 java 8 中的 Stream.generate 静态方法签名的问题

Posted

技术标签:

【中文标题】理解 java 8 中的 Stream.generate 静态方法签名的问题【英文标题】:Problems understanding the Stream.generate static method signature in java 8 【发布时间】:2018-01-28 02:58:50 【问题描述】:

为什么java没有选择这个签名<T> Stream <T> Stream.generate (Supplier <? extends T> supplier)而不是这个<T> Stream <T> Stream.generate (Supplier <T> supplier)

我的意思是下面的例子(不编译)是正确的,因为字符串的提供者在字符序列流中也是有效的吗?

Supplier <String> constantHello = () -> "Hello";

long count = Stream.<CharSequence>generate(constantHello).count();

【问题讨论】:

如果我可以做一个编译的例子(我可以),就不会有问题了哈哈。 a Supplier &lt;String&gt; 生成在Stream &lt;CharSequence&gt; 上下文中有效的字符串对象,因为我们可以通过CharSequence 变量引用String 作为为什么Supplier&lt;? extends T&gt; 在这里会是可取的动机,假设我有一个Supplier&lt;PrivateFooImpl&gt; 并想从我的API 返回一个Stream&lt;Foo&gt;。不过,我怀疑我们是否可以轻松地回答为什么该方法被声明为这样,除非有人像 @StuartMarks 可以解释它。另请注意,您可以通过说 generate(constantHello::get).map(s -&gt; (CharSequence) s) 来解决此问题。 @BoristheSpider Radiodef 的例子表明这实际上是一个合理的用例,我看不出他们不应该支持? extends T 的原因(所以+1 的问题) . @marsouf:使用::get 技巧,您基本上是在创建一个具有那里所需类型的新供应商。 (一个非常简化的解释 - 引擎盖下正在进行一些非常核心的类型推断......) @BoristheSpider 这就是重点。如果他们写了? extends T,那么它可能是(真实的)Stream&lt;CharSequence&gt;。泛型不变的要点是保持类型安全。但是由于流是“只读”的,这在这里不适用。 【参考方案1】:

这是一个错误。见https://bugs.openjdk.java.net/browse/JDK-8132097

已在 java 9 中更正。如您所见here,方法声明现在是

static <T> Stream<T> generate​(Supplier<? extends T> s)

【讨论】:

【参考方案2】:

最好用一个不同的例子来证明。

给定一个Supplier,比如说,一个双精度:

Supplier<Double> generator = Math::random;

当然,我们可以用这个创建一个 Stream 的双打:

Stream<Double> ds = Stream.generate(generator);

但是如果我想要一个Stream 的数字怎么办?毕竟,鉴于 double 是一个数字,只有能够允许这样的事情才有意义:

Stream<Number> ns = Stream.generate(generator);

您的两个签名中的后者不允许编译上述语句,因为generator 不是Supplier&lt;Number&gt;。不过,它是Supplier&lt;Double&gt;,因此是Supplier&lt;? extends Number&gt;

【讨论】:

以上是关于理解 java 8 中的 Stream.generate 静态方法签名的问题的主要内容,如果未能解决你的问题,请参考以下文章

java中的二进制运算简单理解

深入理解Java Class文件格式

全面理解Java中的String数据类型

带你彻底理解Java中的21种锁

Java并发指南13:Java7/8 中的 HashMap 和 ConcurrentHashMap 全解析

深入理解HashMap