Collection.toArray()vs Collection.stream()。toArray() [英] Collection.toArray() vs Collection.stream().toArray()

查看:73
本文介绍了Collection.toArray()vs Collection.stream()。toArray()的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑以下代码:

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);

在我看来,使用流更加简单。

It seems to me that using a stream is much simpler.

因此,我测试了每个的速度。

Therefore, I tested the speed of each.

List<String> myList = Arrays.asList("1", "2", "3");
double start;

start = System.currentTimeMillis();
for (int i = 0; i < 10_000_000; i++) {
    String[] myArray1 = myList.toArray(new String[myList.size()]);
    assert myArray1.length == 3;
}
System.out.println(System.currentTimeMillis() - start);

start = System.currentTimeMillis();
for (int i = 0; i < 10_000_000; i++) {
    String[] myArray2 = myList.stream().toArray(String[]::new);
    assert myArray2.length == 3;
}
System.out.println(System.currentTimeMillis() - start);

结果是使用流的速度大约慢了四倍。在我的机器上,816毫秒(流)与187毫秒(没有流)。我也尝试切换时序语句(myArray1之前的myArray2),这对结果影响不大。为什么这么慢?创建一个 Stream 如此计算密集?

The result is that using the stream is about four times slower. On my machine, 816ms (stream) vs 187ms (no stream). I also tried switching the timing statements around (myArray2 prior to myArray1), which didn't effect the results much. Why is this so much slower? Is creating a Stream so computationally intensive?

我跟着@ Holger的建议并研究了一下(肯定不够)关于JVM测试,阅读这篇文章这篇文章本文,并使用 JMH

I followed @Holger's advice and studied up a bit (surely not enough) on JVM testing, reading this post, this article, this article, and using JMH.

结果(通过JMH):

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);
}




StreamToArrayArrayListBenchmark.testMethod avgt 5 2846.346±32.500 ns / op

StreamToArrayArrayListBenchmark.testMethod avgt 5 2846.346 ± 32.500 ns/op



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]);
}




ToArrayEmptyArrayListBenchmark.testMethod avgt 5 1417.474±20.725 ns / op

ToArrayEmptyArrayListBenchmark.testMethod avgt 5 1417.474 ± 20.725 ns/op



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()]);
}




ToArraySizedArrayListBenchmark.testMethod avgt 5 1853.622±178.351 ns / op

ToArraySizedArrayListBenchmark.testMethod avgt 5 1853.622 ± 178.351 ns/op







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);
}




StreamToArrayLinkedListBenchmark.testMethod avgt 5 4152.003±59.281 ns / op

StreamToArrayLinkedListBenchmark.testMethod avgt 5 4152.003 ± 59.281 ns/op



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]);
}




ToArrayEmptyLinkedListBenchmark.testMethod avgt 5 4089.550±29.880 ns / op

ToArrayEmptyLinkedListBenchmark.testMethod avgt 5 4089.550 ± 29.880 ns/op



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()]);
}




ToArraySizedArrayListBenchmark.testMethod avgt 5 4115.557±93.964 ns / op

ToArraySizedArrayListBenchmark.testMethod avgt 5 4115.557 ± 93.964 ns/op






总结:


To summarize:

              | ArrayList | LinkedList
stream        | 2846      | 4152
toArray sized | 1853      | 4115
toArray empty | 1417      | 4089






使用JMH(可能天真),我'我仍然看到 ArrayList :: toArray 的速度是 Stream :: toArray 的两倍。但是,这似乎是因为 ArrayList 能够执行数组副本,正如@Andreas所指出的那样,因为当源是 LinkedList 结果大致相等。


Using JMH (possibly naively), I'm still seeing that ArrayList::toArray is about twice as fast as Stream::toArray. However, this does seem to be because of the ability of the ArrayList to just do an array copy, as @Andreas pointed out because when the source is a LinkedList the results are about equal.

了解 myList.toArray(new String [0 ])

推荐答案

Arrays.asList() 创建一个固定大小的 List ,它由varargs数组参数直接支持。 Javadoc甚至这样说:

Arrays.asList() creates a fixed-size List that is directly backed by the varargs array parameter. Javadoc even says so:


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

Returns a fixed-size list backed by the specified array.

toArray() 是一个简单的 System.arraycopy( ) 非常快

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

On the other hand, when you do myList.stream().toArray(String[]::new), the size is not known, so the Stream.toArray() method has to consume the stream, collect all the values, then create the array and copy the values into the array. That is a lot slower, and requires a lot more memory.

简而言之,这是浪费资源。

In short, it's a waste of resources.

如果你想要更简单,就不要给出数组大小。它比使用Streams更快,内存更少:

If you want simpler, just don't give the array size. It is still way faster and less memory intensive than using Streams:

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

这篇关于Collection.toArray()vs Collection.stream()。toArray()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆