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