探究下集合类指定初始容量的必要性
2021-05-19 本文已影响0人
尹楷楷
以ArrayList为例,对比下指定初始容量和不指定两种情况对List.add性能的影响
/**
* 指定初始容量后:耗时 1030
*/
ArrayList<Object> list = new ArrayList<Object>();
final int N = 10000000;
list = new ArrayList<Object>(N);
long startTime1 = System.currentTimeMillis();
for (int i = 0; i < N; i++) {
list.add(i);
}
long endTime1 = System.currentTimeMillis();
System.out.println("指定初始容量后:" + (endTime1 - startTime1));
/**
* 不指定容量:耗时 1432
*/
ArrayList<Object> list = new ArrayList<Object>();
final int N = 10000000;
list = new ArrayList<Object>();
long startTime1 = System.currentTimeMillis();
for (int i = 0; i < N; i++) {
list.add(i);
}
long endTime1 = System.currentTimeMillis();
System.out.println("不指定容量:" + (endTime1 - startTime1));
指定容量的List做add操作明显比不指定的快。
ensureCapacity方法
如果List的初始化不是自己掌握的,那么我们在add大量数据之前可以调用 list.ensureCapacity(N); 以减少增量重新分配的次数,提升List的add性能。
ArrayList.ensureCapacity 源码如下:
public void ensureCapacity(int minCapacity) {
int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
// any size if not default element table
? 0
// larger than default for default empty table. It's already
// supposed to be at default size.
: DEFAULT_CAPACITY;
if (minCapacity > minExpand) {
ensureExplicitCapacity(minCapacity);
}
}
下面进行ensureCapacity测试
/**
* 不使用 ensureCapacity耗时 1916
*/
ArrayList<Object> list = new ArrayList<Object>();
final int N = 10000000;
long startTime = System.currentTimeMillis();
for (int i = 0; i < N; i++) {
list.add(i);
}
long endTime = System.currentTimeMillis();
System.out.println("不使用ensureCapacity:"+(endTime - startTime));
/**
* 使用 ensureCapacity 耗时 1089
*/
ArrayList<Object> list = new ArrayList<Object>();
final int N = 10000000;
list = new ArrayList<Object>();
long startTime1 = System.currentTimeMillis();
list.ensureCapacity(N);
for (int i = 0; i < N; i++) {
list.add(i);
}
long endTime1 = System.currentTimeMillis();
System.out.println("使用ensureCapacity方法后:" + (endTime1 - startTime1));
答案显而易见
何况,阿里手册上也有相关信息:
【推荐】集合初始化时,指定集合初始值大小。
说明:HashMap 使用 HashMap(int initialCapacity) 初始化。
正例:initialCapacity = (需要存储的元素个数 / 负载因子) + 1。注意负载因子(即 loader factor)默认
为 0.75,如果暂时无法确定初始值大小,请设置为 16(即默认值)。
反例:HashMap 需要放置 1024 个元素,由于没有设置容量初始大小,随着元素不断增加,容量 7 次被
迫扩大,resize 需要重建 hash 表,严重影响性能。