本文共 1373 字,大约阅读时间需要 4 分钟。
在Java开发中,HashMap是最常用的非同步集合类,其性能至关重要。关于HashMap容量设置的选择,阿里巴巴Java开发手册中提到一个重要建议:在已知HashMap中将要存放的元素数量时,设置合理的初始容量可以显著提升性能。本文将深入分析这个问题,并提供实用的容量设置策略。
HashMap的性能瓶颈主要体现在两方面:一是哈希冲突的概率,二是扩容时的性能开销。默认情况下,HashMap的容量设置为16,这在处理大规模数据时往往不足以应对需求,导致频繁的扩容操作。
通过代码测试可以观察到,未初始化容量的HashMap在存储大量数据时表现出明显的性能下降。例如,在存储10亿个键值对时,未初始化容量的HashMap耗时较长,而初始容量设置为5千万或10亿时,性能显著提升。这证明了合理的容量设置能够有效减少扩容的频率,从而提高整体性能。
HashMap的容量计算机制有一些值得注意的细节。传统的初始化容量设置并非直接使用用户指定的值,而是经过一系列计算后得到一个第一个大于该值的2的幂。具体来说:
计算逻辑
容量计算的逻辑如下: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;
这段代码的作用是找到一个大于cap的最小2的幂数。例如,cap为5时,计算结果为8;cap为9时,计算结果为16。
特殊处理
该逻辑在JDK 1.7和1.8中有所不同。在1.7中,容量设置会在第一次put操作时生效,而在1.8中,容量设置会直接生效。这一点需要开发者注意,尤其是在跨版本兼容性要求较高的项目中。 在已知将要存储的元素数量(expectedSize)的情况下,如何选择合适的容量是一个关键问题。《阿里巴巴Java开发手册》建议采用以下公式计算初始容量:
int capacity = (expectedSize / 0.75F) + 1;
这个公式考虑了HashMap默认的负载因子(0.75),确保在存储元素时减少扩容的次数。例如,当expectedSize为10时,计算结果为14,这样可以避免在存储6个元素时就触发扩容的情况。
在开发过程中,合理设置HashMap的初始容量可以显著提升性能。但需要注意的是,JDK会对初始容量进行自动调整,最终返回一个大于指定值的第一个2的幂数。因此,在实际应用中,可以通过公式expectedSize / 0.75F + 1.0F计算一个合理的初始容量。
putAll方法采用了expectedSize / 0.75F + 1.0F公式,而put方法并未采用这个公式?这背后反映了JDK在不同操作的性能优化策略。putAll方法需要一次性批量存储大量数据,因此采用较为保守的容量计算公式以确保稳定性。而put方法则更注重灵活性,允许用户根据具体需求动态调整容量。
转载地址:http://prouz.baihongyu.com/