gpt4 book ai didi

java - Collection.toArray() 与 Collection.stream().toArray()

转载 作者:行者123 更新时间:2023-12-04 21:28:24 27 4
gpt4 key购买 nike

考虑以下代码:

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

在我看来,使用流要简单得多。

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

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 毫秒(无流)。我还尝试切换计时语句(myArray2 在 myArray1 之前),这对结果影响不大。为什么这么慢?创建 Stream 的计算量如此之大吗?

我听从了@Holger 的建议并研究了一些(当然还不够)JVM 测试,阅读 this post , this article , this article ,并使用 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

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

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


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

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

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


总结:

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

使用 JMH(可能天真),我仍然看到 ArrayList::toArray 大约是 Stream::toArray 的两倍。然而,这似乎是因为 ArrayList 只进行数组复制的能力,正如@Andreas 指出的那样,因为当源是 LinkedList 时,结果是大致相等。

了解myList.toArray(new String[0])绝对是件好事。

最佳答案

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

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

其对toArray()的实现是一个简单的 System.arraycopy() . 非常快

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

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

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

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

关于java - Collection.toArray() 与 Collection.stream().toArray(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42012471/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com