Java Collection.toArray()与Collection.stream().toArray()的比较

Java Collection.toArray()与Collection.stream().toArray()的比较,java,collections,java-stream,Java,Collections,Java Stream,考虑以下代码: List<String> myList = Arrays.asList(1, 2, 3); String[] myArray1 = myList.toArray(new String[myList.size()]); String[] myArray2 = myList.stream().toArray(String[]::new); assert Arrays.equals(myArray1, myArray2); 流向ArrayArrayListBenchmar

考虑以下代码:

List<String> myList = Arrays.asList(1, 2, 3);
String[] myArray1 = myList.toArray(new String[myList.size()]);
String[] myArray2 = myList.stream().toArray(String[]::new);
assert Arrays.equals(myArray1, myArray2);
流向ArrayArrayListBenchmark.testMethod avgt 5 2846.346±32.500纳秒/秒


使用JMH(可能很幼稚),我仍然看到
ArrayList::toArray
的速度大约是
Stream::toArray
的两倍。然而,正如@Andreas指出的,这似乎是因为
ArrayList
能够只进行数组复制,因为当源是
LinkedList
时,结果大致相同


了解myList.toArray(新字符串[0])

无疑是件好事。在后台,流比普通数组复杂得多。编译器会变得更好,但目前,顺序for循环应该比流操作更快

对用于实现流的流管道有一定的背景知识。这有助于理解其背后的复杂性

streams的优点是代码更清晰,更容易并行化。

创建一个固定大小的
列表,该列表直接由varargs数组参数支持。Javadoc甚至这样说:

返回指定数组支持的固定大小列表

它的实现是一个简单的过程非常快

另一方面,当您执行myList.stream().toArray(String[]::new)
时,大小未知,因此该方法必须使用流,收集所有值,然后创建数组并将值复制到数组中。这要慢很多,需要更多的内存

简言之,这是对资源的浪费

如果您想要更简单,就不要给出数组大小。它仍然比使用流更快,内存占用更少:

String[] myArray1 = myList.toArray(new String[0]);

如果您使用
Arrays.stream()
?@JoshLee在我的真实代码中,我有一个列表,我正试图将其转换为数组。我不知道我将如何使用array.stream()来处理它?@Holger你是说我的结论是错误的吗?我并不是在问如何进行基准测试——我假设我的基准测试不是100%准确。我真的是在问
流的开销问题,这在另一个问题中没有涉及。我们不是在说“100%准确”,你违反了这里提到的每一条规则。当然,从这样一个根本上被打破的基准中得出的结论是错误的。对于现实生活中的用例,这些方法之间的实际差异接近于零。@Holger好的——这是对我问题的合理回答。我还是不明白这怎么会是一个复制品。如果您的答案是“您的基准测试是错误的——它们是等价的”,为什么不在回答中这样说呢?我不知道您可以使用空数组的toArray。谢谢你的提示!给它一个预先调整大小的数组似乎速度差不多。我只是用LinkedList而不是Arrays.asList()尝试了一下,行为是一样的,LinkedList和ArrayList的时间几乎是一样的。似乎所有的开销都在流中。不管你如何分割它(可以说),数组副本只是对JVM的一次调用,而任何库解决方案都至少会有一个显式循环。@JoshLee我理解这一点——但是,证据不支持速度是由于它是一个ArrayList的说法。LinkedList::toArray(继承自AbstractList::toArray)正在迭代列表以填充数组。它不是数组副本。然而,它远没有
版本那么糟糕。由
列表
创建的流,没有
过滤器
等,它知道它的大小,并在
toArray
实现中使用它。不过,在未优化的执行中,它可能比任何硬编码操作都要慢,因为这个有缺陷的基准记录了加载、验证和初始化
类及其所有内部使用的类所需的时间,以及
LambdaMetaFactory
及其依赖项。修复了文章链接>@Filip谢谢,我修复了它。
private static final List<String> myList = IntStream.range(1, 1000).mapToObj(String::valueOf).collect(Collectors.toList());

@Benchmark
public void testMethod() {
    String[] myArray = myArrayList.stream().toArray(String[]::new);
}
private static final List<String> myList = IntStream.range(1, 1000).mapToObj(String::valueOf).collect(Collectors.toList());

@Benchmark
public void testMethod() {
    String[] myArray = myArrayList.toArray(new String[0]);
}
private static final List<String> myList = IntStream.range(1, 1000).mapToObj(String::valueOf).collect(Collectors.toList());

@Benchmark
public void testMethod() {
    String[] myArray = myArrayList.toArray(new String[myList.size()]);
}
private static final List<String> myList = new LinkedList<>(IntStream.range(1, 1000).mapToObj(String::valueOf).collect(Collectors.toList()));

@Benchmark
public void testMethod() {
    String[] myArray = myArrayList.stream().toArray(String[]::new);
}
private static final List<String> myList = new LinkedList<>(IntStream.range(1, 1000).mapToObj(String::valueOf).collect(Collectors.toList()));

@Benchmark
public void testMethod() {
    String[] myArray = myArrayList.toArray(new String[0]);
}
private static final List<String> myList = new LinkedList<>(IntStream.range(1, 1000).mapToObj(String::valueOf).collect(Collectors.toList()));

@Benchmark
public void testMethod() {
    String[] myArray = myArrayList.toArray(new String[myList.size()]);
}
              | ArrayList | LinkedList
stream        | 2846      | 4152
toArray sized | 1853      | 4115
toArray empty | 1417      | 4089
String[] myArray1 = myList.toArray(new String[0]);