扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
这篇文章给大家介绍java中怎么初始化hashmap容量,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。
为耿马等地区用户提供了全套网页设计制作服务,及耿马网站建设行业解决方案。主营业务为成都网站设计、成都网站制作、耿马网站设计,以传统方式定制建设网站,并提供域名空间备案等一条龙服务,秉承以专业、用心的态度为用户提供真诚的服务。我们深信只要达到每一位用户的要求,就会得到认可,从而选择与我们长期合作。这样,我们也可以走得更远!我们先来写一段代码在JDK1.7的环境下运行,来分别测试下,在不指定初始化容量和指定初始化容量的情况下性能情况的不同。
public static void main(String[] args) { int aHundredMillion = 10000000; // 未初始化容量 Map
从以上的代码不难理解,我们创建了3个HashMap,分别使用默认的容量(16)、使用元素个数的一半(5千万)作为初始容量和使用元素个数(一亿)作为初始容量进行初始化,然后分别向其中put一亿个KV。
从上面的打印结果中可以得到一个初步的结论:在已知HashMap中将要存放的KV个数的时候,设置一个合理的初始化容量可以有效地提高性能。下面我们来简单分析一下原因。
我们知道,HashMap是有扩容机制的。所谓的扩容机制,指的是当达到扩容条件的时候,HashMap就会自动进行扩容。而HashMap的扩容条件就是当HashMap中的元素个数(Size)超过临界值(Threshold)的情况下就会自动扩容。
threshold = loadFactor * capacity
在元素个数超过临界值的情况下,随着元素的不断增加,HashMap就会发生扩容,而HashMap中的扩容机制决定了每次扩容都需要重建hash表,这一操作需要消耗大量资源,是非常影响性能的。因此,如果我们没有设置初始的容量大小,HashMap就可能会不断发生扩容,也就使得程序的性能降低了。
另外,在上面的代码中我们会发现,同样是设置了初始化容量,设置的数值不同也会影响性能,那么当我们已知HashMap中即将存放的KV个数的时候,容量的设置就成了一个问题。
HashMap中容量的初始化
开头提到,在默认的情况下,当我们设置HashMap的初始化容量时,实际上HashMap会采用第一个大于该数值的2的幂作为初始化容量。
Map
当初始化的容量设置成1的时候,通过反射取出来的capacity却是2。在JDK1.8中,如果我们传入的初始化容量为1,实际上设置的结果也是1。上面的代码打印的结果为2的原因,是代码中给map塞入值的操作导致了扩容,容量从1扩容到了2。事实上,在JDK1.7和JDK1.8中,HashMap初始化容量(capacity)的时机不同。在JDK1.8中,调用HashMap的构造函数定义HashMap的时候,就会进行容量的设定。而在JDK1.7中,要等到第一次put操作时才进行这一操作。
因此,当我们通过HashMap(int initialCapacity)设置初始容量的时候,HashMap并不一定会直接采用我们传入的数值,而是经过计算,得到一个新值,目的是提高hash的效率。比如1->1、3->4、7->8和9->16。
HashMap中初始容量的合理值
通过上面的分析我们可以知道,当我们使用HashMap(int initialCapacity)来初始化容量的时候,JDK会默认帮我们计算一个相对合理的值当做初始容量。那么,是不是我们只需要把已知的HashMap中即将存放的元素个数直接传给initialCapacity就可以了呢?
initialCapacity = (需要存储的元素个数 / 负载因子) + 1
这里的负载因子就是loaderFactor,默认值为0.75。
initialCapacity = expectedSize / 0.75F + 1.0F
上面这个公式是《阿里巴巴Java开发手册》中的一个建议,在Guava中也是提供了相同的算法,更甚之,这个算法实际上是JDK8中putAll()方法的实现。这是公式的得出是因为,当HashMap内部维护的哈希表的容量达到75%时(默认情况下),就会触发rehash(重建hash表)操作。而rehash的过程是比较耗费时间的。所以初始化容量要设置成expectedSize/0.75 + 1的话,可以有效地减少冲突,也可以减小误差。
总结
当我们想要在代码中创建一个HashMap的时候,如果我们已知这个Map中即将存放的元素个数,给HashMap设置初始容量可以在一定程度上提升效率。
但是,JDK并不会直接拿用户传进来的数字当做默认容量,而是会进行一番运算,最终得到一个2的幂。而为了较大程度地避免扩容带来的性能消耗,通常是建议可以把默认容量的数字设置成expectedSize / 0.75F + 1.0F。
在日常开发中,可以使用Guava提供的一个方法来创建一个HashMap,计算的过程Guava会帮我们完成。
Map
最后要说的一点是,这种算法实际上是一种使用内存换取性能的做法,在真正的应用场景中要考虑到内存的影响。
关于java中怎么初始化hashmap容量就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流