为什么 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
的三个重载
Object[] toArray()
T[] toArray(IntFunction<T[]> generator)
T[] toArray(T[] a)
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[]>)
版本似乎没有太多好处。
虽然 Collection
API 提供了 toArray
Object[] toArray()
T[] toArray(IntFunction<T[]> generator)
T[] toArray(T[] a)
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 alsoSUBSIZED
)的流(Spliterator
),因此您不知道拆分后将数据放在哪里
在这两种情况下,实现仍然必须创建新数组并通过复制数据来完成,这违背了上述要求的目的。
在许多情况下,您正在使用未知大小的流(一个简单的 filter()
或 flatMap()
将删除 属性),您通常会陷入上述情况限制。
此外,即使对于已知大小的情况,人们也经常在调用 Collection.toArray(T[])
时分配一个大小合适的新数组。 This was actually counter-productive 在较新版本的 JVM 中,因此在 Stream API.
最后,如果我们删除填充提供的数组的要求,toArray(IntFunction<T[]>)
版本似乎没有太多好处。