Java中的toArray与stream.toArray有什么性能差异

Nis*_*ara 3 java arrays list java-8 java-stream

我需要将ID列表转换为ID数组。我可以通过多种方式来做到这一点,但不确定应该使用哪种方式。

说,

1. ids.stream().toArray(Id[]::new)
2. ids.toArray(new Id[ids.length])
Run Code Online (Sandbox Code Playgroud)

哪一个效率更高?为什么?

Eug*_*ene 5

引入Collection::toArray了具有以下实现的java-11 :

default <T> T[] toArray(IntFunction<T[]> generator) {
    return toArray(generator.apply(0));
}
Run Code Online (Sandbox Code Playgroud)

为了使它更简单,实际上是在做:ids.toArray(new Id[0]); 即-未指定总预期大小。

这比指定大小要快,而且不直观。但与以下事实有关:如果JVM可以证明正在分配的数组将被紧随其后的某些复制所覆盖,则它不必对数组进行初始置零,而事实证明是然后指定初始大小(必须进行归零的位置)更快。

流方法将具有(或尝试猜测一个估计值)流内部将计算的初始大小,因为:

 ids.stream().toArray(Id[]::new)
Run Code Online (Sandbox Code Playgroud)

实际上是:

 ids.stream().toArray(size -> Id[size]);
Run Code Online (Sandbox Code Playgroud)

size根据a的内部特征,这是已知的或估计的Spliterator。如果流报告了SIZED特征(例如在您的简单情况下),那么就很容易size知道。另一方面,如果SIZED不存在此元素,则流内部将仅估计将存在多少个元素,在这种情况下,将使用隐藏的新集合来捕获称为的元素SpinedBuffer

您可以在此处阅读更多内容,但是这种方法ids.toArray(new Id[0])将是最快的。

  • 并非每个Collection都会产生SIZED流,即并发collection不会。但是对于并发集合,除非应用程序可以在操作期间排除并发修改,否则ids.toArray(new Id [ids.size()])甚至会被破坏。因此,归结为“ ids.toArray(new Id [0])”是最简单,最不容易出错且最有效的解决方案。 (4认同)