简体   繁体   English

JMH - List#addAll 比 ArrayList#new 快吗?

[英]JMH - List#addAll faster than ArrayList#new?

I have quite a simple JMH Benchmark, I have read left and right that using the constructor of collections should be faster than using the addAll method.我有一个非常简单的 JMH Benchmark,我左右阅读过,使用 collections 的构造函数应该比使用addAll方法更快。

However, my benchmark tends to prove the contrary.然而,我的基准往往证明相反。

Any explanation on that?对此有何解释?

@State(Scope.Benchmark)
public static class Strings {
    public String string = "String";
    public List<String> strings = Arrays.asList("String123", "String456", "String789");
}

@Benchmark
@Fork(value = 5, warmups = 3)
public List<String> withStreams(Strings input) {
    return Stream.concat(Stream.of(input.string), input.strings.stream())
            .collect(Collectors.toList());
}

@Benchmark
@Fork(value = 5, warmups = 3)
public List<String> withoutStreamsButWithConstructor(Strings input) {
    List<String> result = new ArrayList<>(input.strings);
    result.add(input.string);
    return result;
}

@Benchmark
@Fork(value = 5, warmups = 3)
public List<String> withoutStreams(Strings input) {
    List<String> result = new ArrayList<>();
    result.add(input.string);
    result.addAll(input.strings);
    return result;
}

PS: The example with Streams is just an experiment (in fact the actual things I wanted to be sure of) PS:Streams的例子只是一个实验(实际上是我想确定的实际事情)

Results结果

# Run complete. Total time: 00:16:31

Benchmark                              Mode  Cnt         Score        Error  Units
App.withStreams                       thrpt  100  12649053,043 ± 222716,712  ops/s
App.withoutStreams                    thrpt  100  50572729,531 ± 324271,706  ops/s
App.withoutStreamsButWithConstructor  thrpt  100  30179733,201 ± 380273,095  ops/s

Update更新

Added the following benchmark to the family为家庭添加了以下基准

@Benchmark
@Fork(value = 5, warmups = 3)
public List<String> withoutStreamsWithAddAfter(Strings input) {
    List<String> result = new ArrayList<>();
    result.addAll(input.strings);
    result.add(input.string);
    return result;
}

And I now get我现在得到

# Run complete. Total time: 00:22:00

Benchmark                              Mode  Cnt         Score        Error  Units
App.withStreams                       thrpt  100  13560464,180 ± 201012,539  ops/s
App.withoutStreams                    thrpt  100  47490197,224 ± 864545,886  ops/s
App.withoutStreamsButWithConstructor  thrpt  100  29412182,733 ± 346228,939  ops/s
App.withoutStreamsWithAddAfter        thrpt  100  31030909,677 ±  81494,995  ops/s

So the withoutStreams is the most performant one anyway所以withoutStreams无论如何都是性能最好的


Update #2更新#2

I've tried with the following List<String>我试过以下List<String>

@State(Scope.Benchmark)
public static class Strings {
    public String string = "String";
    public List<String> strings = Arrays.asList("String123", "String456", "String789", "StringAbc", "StringDef", "StringGhi", "StringJkl", "StringMno", "StringPqr", "StringStu");
}

And now the results are indeed better for the constructor @Benchmark现在结果对于构造函数@Benchmark确实更好

# Run complete. Total time: 00:22:01

Benchmark                              Mode  Cnt         Score        Error  Units
App.withStreams                       thrpt  100   7291967,397 ± 330614,125  ops/s
App.withoutStreams                    thrpt  100  23575768,665 ± 127039,282  ops/s
App.withoutStreamsButWithConstructor  thrpt  100  27046342,511 ± 182227,005  ops/s
App.withoutStreamsWithAddAfter        thrpt  100  17873682,945 ± 170786,259  ops/s

I suspect the reason lies in how ArrayList is implemented.我怀疑原因在于 ArrayList 是如何实现的。

withoutStreamsButWithConstructor creates an array of size 1, and when you call addAll , a new array of size 4 is created, the first element is copied over and the other elements are then added. withoutStreamsButWithConstructor创建一个大小为 1 的数组,当您调用addAll时,将创建一个大小为 4 的新数组,复制第一个元素,然后添加其他元素。

withoutStreams creates an array of size 10 (default capacity) and no resizing is required. withoutStreams创建一个大小为 10(默认容量)的数组,不需要调整大小。

If strings contained 10 elements, one array resizing would be required in both methods and I suspect the results would be closer.如果strings包含 10 个元素,则两种方法都需要调整一个数组大小,我怀疑结果会更接近。

More generally, if performance is important, sizing the list correctly with the constructor that takes an int can make a difference.更一般地说,如果性能很重要,那么使用采用int的构造函数正确调整列表的大小会有所不同。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Java 8 数组列表。 哪个更快? 在索引 0 处插入一项或使用一项创建新列表并将所有添加到新列表? - Java 8 ArrayList. Which is it faster? Insert one item at index 0 or create new List with one item and addAll to the new List? 使用Arraylist addAll()创建具有不同引用的新对象的新列表 - Using Arraylist addAll() to create a new list with new objects with different reference 为什么Collections.addAll应该比c.addAll更快 - Why is Collections.addAll supposed to be faster than c.addAll 用于内容复制的ArrayList.addAll(list)与新ArrayList &lt;&gt;(list)之间的区别 - Difference between ArrayList.addAll(list) and new ArrayList<>(list) for content copying 为什么JMH说返回1比返回0更快 - Why is JMH saying that returning 1 is faster than returning 0 Java addAll(集合)与新的ArrayList(集合) - Java addAll(collection) vs new ArrayList(collection) 在列表中间插入的情况下,LinkedList 真的比 ArrayList 快吗? - Is LinkedList really faster than ArrayList in the case of insertion in the middle of list? MySQL JDBC查询比JMH测试中的查询要快得多 - MySQL JDBC query much faster than it should be in JMH test ArrayList.addAll()ConcurrentModificationException - ArrayList.addAll() ConcurrentModificationException ArrayList-add / Array-get列表生成器何时会比ArrayList更快? - When would ArrayList-add/Array-get List Builder be faster than ArrayList?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM