理解Stream.generate静态方法的签名存在困难

10
为什么Java没有选择这个签名 <T> Stream<T> Stream.generate(Supplier<? extends T> supplier) 而是选择了这个 <T> Stream<T> Stream.generate(Supplier<T> supplier) ? 我的意思是下面的例子(不能编译)是正确的,因为提供String也适用于CharSequence流,不是吗?
Supplier<String> constantHello = () -> "Hello";

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

2
如果我能编写一个可以编译的示例(我可以做到),那就没有问题了,哈哈。 - marsouf
1
一个 Supplier <String> 生成的字符串对象在 Stream <CharSequence> 的上下文中是有效的,因为我们可以通过 CharSequence 变量引用一个 String - marsouf
3
作为为什么在这里使用 Supplier<? extends T> 是有用的动机,假设我有一个 Supplier<PrivateFooImpl> 并且想要从我的 API 返回一个 Stream<Foo>。我怀疑除非像 @StuartMarks 这样的人能够解释,否则我们很难回答为什么方法被声明成这样。还要注意,你可以通过说 generate(constantHello::get).map(s -> (CharSequence) s) 来绕过这个问题。 - Radiodef
2
@BoristheSpider Radiodef的例子表明这实际上是一个合理的用例。我不明白为什么他们不支持 ? extends T,所以对于这个问题我点赞(+1)。 @marsouf :使用 ::get 技巧,你基本上创建了一个新的供应商,其类型在那里是必需的。(一个非常简化的解释 - 那里有一些相当强大的类型推断正在进行之中……) - Marco13
2
@BoristheSpider 这就是关键所在。如果他们写成了 ? extends T,那么它可能是一个(真正的)Stream<CharSequence>。泛型不变的主要目的是保持类型安全。但由于流是“只读”的,因此这里不适用。 - Marco13
显示剩余17条评论
2个回答

10

0
最好用另一个例子来演示。
假设有一个供应商,例如一个double类型的Supplier
Supplier<Double> generator = Math::random;

当然,我们可以使用以下代码创建一个双精度的Stream

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

但是如果我想要一个数字的呢?毕竟,既然double是一个数字,允许像这样的东西只是有意义的:

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

你的后一个签名不会让上面的语句编译通过,因为“generator”不是“Supplier”。但它确实是一个“Supplier”,因此也是一个“Supplier”。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接