为什么 Java Stream API 省略 'toArray(T[] a)' 重载以写入现有数组?

Why does the Java Stream API omit the 'toArray(T[] a)' overload for writing to an existing array?

虽然 Collection API 提供了 toArray

的三个重载

Stream API 只提供了其中的前两个。也就是说,它不提供使用现有数组作为流到数组转换的 return 值的方法。

--> Stream中省略toArray(T[] a)是什么原因?

我想主要原因是流的功能精神,这会产生像写入现有数组这样的副作用。这个对吗 ?还有其他原因会使其他两个版本更受欢迎吗?也许甚至有一些原因使它们在 Collection 上也更受欢迎?

使用 Collection.toArray(T[]) 的常见模式(至少根据我的观察)是这样的:

var array = list.toArray( new T[0] );

意味着提供了一个大小为 0 的空数组。

使用现有数组调用 toArray() 允许 return 正确类型的数组,与 Object 的数组相反。除了通过 'sample' 之外,没有其他方法可以将所需的 return 类型赋予方法。您可以改为考虑 toArray( Class<T> elementType ),但如果 T 也是参数化类型,那将无法正常工作。

引入 Lambda 时,带有 IntFunction<T[]> 的变体在其功能中替换了现有数组的变体,因此在 Stream 中省略了它。我希望 Collection.toArray(T[]) 很快就会被弃用,并且会随着即将推出的 LTS 版本之一被删除——当然不是下一个版本,也不是下一个版本之后的版本!

如果我们考虑Collection.toArray(T[])的规格:

[…] If the collection fits in the specified array, it is returned therein. Otherwise, a new array is allocated with the runtime type of the specified array and the size of this collection.

然而,有一些问题会阻止对流进行同样的操作:

  • 实现无法提前知道未知大小的流是否适合
  • 使用并行流,拆分已知大小(即SIZED) could lead to 2 spliterators of unknown size if the original spliterator is not also SUBSIZED)的流(Spliterator),因此您不知道拆分后将数据放在哪里

在这两种情况下,实现仍然必须创建新数组并通过复制数据来完成,这违背了上述要求的目的。

在许多情况下,您正在使用未知大小的流(一个简单的 filter()flatMap() 将删除 属性),您通常会陷入上述情况限制。

此外,即使对于已知大小的情况,人们也经常在调用 Collection.toArray(T[]) 时分配一个大小合适的新数组。 This was actually counter-productive 在较新版本的 JVM 中,因此在 Stream API.

中带来同样的问题将是一件坏事

最后,如果我们删除填充提供的数组的要求,toArray(IntFunction<T[]>) 版本似乎没有太多好处。