1. Collections.addAll()比arrays.addAll()更快吗?
在《Java核心编程》这本书中,“持有对象”这一章有个地方讲到:
Collections.addAll()比arrays.addAll()方法快得多!
我们知道,Collections是一个工具类,它提供了一组操作集合类的静态方法,包括排序、交换元素、拷贝、最大值、最小值等,使用起来非常方便。addAll()方法就是其中之一,它用来将一组元素添到一个集合中:
List arrays = new ArrayList<>();
Collections.addAll(arrays, "hello", "world");
而arrays.addAll()方法,是List对象的一个方法,它实现的功能与Collections.addAll()类似,也是将一组元素添加到数组中:
List arrays = new ArrayList<>();
arrays.addAll(Arrays.asList("hello", "world"));
2. 是不是真的更快?
尽信书不如无书,书上虽然是这样说的,那是不是真的Collections.addAll()比arrays.addAll()性能好很多呢?我们不妨来测试一下:
public class Test {
public static void main(String[] args) {
//循环次数
int count = 100000000;
System.out.println("Collections.addAll()耗时:" + collectionsTest(count) + "ms");
System.out.println("arrays.addAll()耗时:" + arraysTest(count) + "ms");
}
public static long collectionsTest(int count) {
long startTime = System.currentTimeMillis();
for (int i = 0; i < count; i++) {
List arrays = new ArrayList<>();
Collections.addAll(arrays, "hello", "world");
}
return System.currentTimeMillis() - startTime;
}
public static long arraysTest(int count) {
long startTime = System.currentTimeMillis();
for (int i = 0; i < count; i++) {
List arrays = new ArrayList<>();
arrays.addAll(Arrays.asList("hello", "world"));
}
return System.currentTimeMillis() - startTime;
}
}
我们使用这两个方法,向其中添加元素,分别循环一个小目标,得出耗时对比:
arrays.addAll()耗时:3324ms
Collections.addAll()耗时:2034ms
可以看到,这两个方法的耗时差距还是很大的,arrays.addAll()的耗时大概是Collections.addAll()的1.6倍左右。看来Bruce Eckel没有骗我,他是个诚实的人,说的确实对。
3. 为什么它这么快?
好了,是不是的问题已经解决了,我们已经知道,Collections.addAll()确实比arrays.addAll()方法快很多,可是:
Why?
让我们回过头来再看一眼刚才的代码,首先是Collections.addAll():
List arrays = new ArrayList<>();
Collections.addAll(arrays, "hello", "world");
public static boolean addAll(Collection super T> c, T... elements) {
boolean result = false;
for (T element : elements)
result |= c.add(element);
return result;
}
这两行代码很简单,就做了两件事情:
创建arrays
调用addAll()
使用数组迭代器,将元素添加到arrays中
然后是arrays.addAll():
List arrays = new ArrayList<>();
arrays.addAll(Arrays.asList("hello", "world"));
public boolean addAll(Collection extends E> c) {
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityInternal(size + numNew); // Increments modCount
System.arraycopy(a, 0, elementData, size, numNew);
size += numNew;
return numNew != 0;
}
它做了什么呢?可以看到:
创建arrays
使用Arrays.asList()新创建了一个集合
调用addAll()
使用c.toArray()方法复制入参到a中。(耗时较长)
使用ensureCapacityInternal()校验是否溢出
使用System.arraycopy()拷贝a中新传入的元素到数组容器elementData中
综上所述,可以得出,Collections.addAll()和arrays.addAll()主要有两种差别:
arrays.addAll()方法会在调用前使用Arrays.asList()多创建一个集合
在两个addAll()方法内部,arrays.addAll()会比Collections.addAll()多一些集合创建,数组长度校验的操作。
因此,大家在开发过程中,还是尽量使用Collections.addAll(),可以获得更好的性能。