阿里巴巴为什么让初始化集合时必须指定大小?
哈喽,亲爱的小伙伴们,技术学磊哥,进步没得说!欢迎来到新一期的性能解读系列,我是磊哥。
今天给大家带来的是关于阿里巴巴《Java开发手册》泰山版(最新)中关于集合初始化时的性能建议。
阿里巴巴《Java开发手册》第 1 章编程规范,第 6 节集合处理的第 17 条规定如下:
【推荐】集合初始化时,指定集合初始值大小。
说明:HashMap 使用 HashMap(int initialCapacity) 初始化,如果暂时无法确定集合大小,那么指定默认值(16)即可。
正例:initialCapacity = (需要存储的元素个数 / 负载因子) + 1。注意负载因子(即 loader factor)默认为 0.75,如果暂时无法确定初始值大小,请设置为 16(即默认值)。
反例:HashMap 需要放置 1024 个元素,由于没有设置容量初始大小,随着元素不断增加,容量 7 次被迫扩大,resize 需要重建 hash 表。当放置的集合元素个数达千万级别时,不断扩容会严重影响性能。
规范解读
此规范的主要目的完全是出于性能考虑,查看 HashMap
的源码也就可以发现此规范的原因,如果我们能为集合设置合理的大小就可以避免 HashMap
的扩容操作,而 HashMap
的扩容方法 resize
有很多逻辑判断和业务操作,如果设置了合理的大小就可以避免执行更多的代码,因此就可以更大限度的提高集合的执行效率,HashMap
的 resize
源码如下:
性能评测
接下来我们来测试一下设置 size
的性能和不设置 size
的性能差别,我们已知需要插入 1024 个数据,根据默认的负载因子 0.75 和公式 (存储元素个数/负载因子)+1
得出需要设置的大小为 1367(取整)。
小贴士:公式“(存储元素个数/负载因子)+1”说明:因为 HashMap 的实际存储量等于:元素个数*负载因子,为了防止 HashMap 扩容,所以公式必须是“(存储元素个数/负载因子)+1”才能防止动态扩容。
本文我们依旧使用 Oracle 官方提供的 JMH(Java Microbenchmark Harness,JAVA 微基准测试套件)测试框架,首先现在 pom.xml 中添加 JMH 引用,配置如下:
然后编写完整的测试代码:
测试结果如下:
从上述结果可以看出,设置了大小的 HashMap
的性能约是没有设置大小的 1.29 倍。
总结
在初始化集合时,如果已知集合的数量,那么一定要在初始化时设置集合的容量大小,这样就可以有效的提高集合的性能,但需要注意的是 HashMap
的实际存储量是“元素个数*负载因子”,而负载因子默认是 0.75,因此在设置大小时,要使用“(存储元素个数/负载因子)+1”的公式计算出正确的值再进行设置。
版权声明: 本文为 InfoQ 作者【王磊】的原创文章。
原文链接:【http://xie.infoq.cn/article/00915751db9b6cbd23a24e5df】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论