一、概述
我们使用idea安全插件检测出hashMap容量需要进行初始化,因此本篇文章就探讨该内容,到底应不应该设置HashMap的默认容量?如果真的要设置HashMap的初始容量,我们应该设置多少?
二、为什么要设置HashMap的初始化容量
先看《阿里巴巴开发手册》这样介绍到:
【推荐】集合初始化时,指定集合初始值大小。 说明:HashMap使用HashMap(int initialCapacity) 初始化。
现进行测试在不指定初始化容量和指定初始化容量的情况下性能情况如何(JDK 版本不一样,生成的结果可能不相同,以下是jdk1.8.0_181测试所生成的结果)。
public static void main(String[] args) {
int million =1000000;
Map map =new HashMap<>();
long s1 = System.currentTimeMillis();
for (int i =0; i < million; i++) {
map.put(i, i);
}
long s2 = System.currentTimeMillis();
System.out.println("未初始化容量,耗时 : " + (s2 - s1));
Map mapOne =new HashMap<>(million /2);
long s5 = System.currentTimeMillis();
for (int i =0; i < million; i++) {
mapOne.put(i, i);
}
long s6 = System.currentTimeMillis();
System.out.println("初始化容量500000,耗时 : " + (s6 - s5));
Map mapTwo =new HashMap<>(million);
long s3 = System.currentTimeMillis();
for (int i =0; i < million; i++) {
mapTwo.put(i, i);
}
long s4 = System.currentTimeMillis();
System.out.println("初始化容量为1000000,耗时 : " + (s4 - s3));
}
测试结果从结果中,我们可以知道,在已知HashMap中将要存放的KV个数的时候,设置一个合理的初始化容量可以有效的提高性能。
当然,以上结论也是有理论支撑的。深入理解HashMap底层原理我们知道,HashMap有扩容机制,就是当达到扩容条件时会进行扩容。HashMap的扩容条件就是当HashMap中的元素个数(size)超过临界值(threshold)时就会自动扩容。在HashMap中,threshold = loadFactor * capacity。
所以,如果我们没有设置初始容量大小,随着元素的不断增加,HashMap会发生多次扩容,而HashMap中的扩容机制决定了每次扩容都需要重建hash表,是非常影响性能的。
从上面的代码示例中,我们还发现,同样是设置初始化容量,设置的数值不同也会影响性能,那么当我们已知HashMap中即将存放的KV个数的时候,容量设置成多少为好呢?
备注:
JDK1.8初始化容量和负载因子参考如下:
private static final int initCapacity =11;
private static final double loadFactor =0.75;
三、HashMap容量的初始化
不管是Jdk 1.7还是Jdk 1.8,计算初始化容量的算法其实是如出一辙的,主要代码如下:
static final int tableSizeFor(int cap) {
int n = cap -1;
n |= n >>>1;
n |= n >>>2;
n |= n >>>4;
n |= n >>>8;
n |= n >>>16;
return (n <0) ?1 : (n >=MAXIMUM_CAPACITY) ?MAXIMUM_CAPACITY : n +1;
}
备注:e右移1位: e>>1 :相当于除以2然后取整。
上面的算法目的挺简单,就是:根据用户传入的容量值(代码中的cap),通过计算,得到第一个比他大的2的幂并返回。
聪明的读者们,如果让你设计这个算法你准备如何计算?如果你想到二进制的话,那就很简单了。举几个例子看一下:
正例:initialCapacity = (需要存储的元素个数 / 负载因子) + 1。注意 负载因子(即loader factor)默认为 0.75,如果 暂时无法 确定 初始值大小,请设置为 16(即默认值)。
反例: HashMap需要 放置 1024个元素, 由于 没有设置容量 初始大小,随着元素不断增加容 量 7次被迫扩大, resize需要重建 hash表,严重影响性能。
网友评论