如何给HashMap设置初始化容量

 

在脉脉上看到一个帖子,大致是说,leader的代码在创建HashMap对象时,会主动设置初始容量大小,不知道这么操作到底对不对。

 

 

是否需要设置初始容量

答案是:如有必要,尽量设置

为什么?因为随着元素的增加,Map会进行多次resize(扩容),影响性能。假如我们已经知道要添加的元素数量,创建Map对象就将容量设置到位,就可避免resize操作。

这也是阿里的Java开发手册中,明确推荐“集合初始化时,指定集合初始值大小”。并且推荐设置初始容量为initialCapacity=(需要存储的元素个数 / 负载因子) + 1

 

 

 如何设置初始容量

根据阿里开发手册的推荐,初始容量设置为initialCapacity=(需要存储的元素个数 / 负载因子) + 1,为何要如此设置呢?

如帖子中所说

比如给mybatis传5个参,就new HashMap<>(5)

在创建对象时,会将实际的容量值,设置为比该容量值(5)大且最接近的2的幂(也就是8)。

在添加元素时,当元素个数大于容量阈值(容量阈值 = 容量值 * 负载因子)时,HashMap会进行扩容

此处添加的元素个数 5 < 8 * 0.75 ,因此不会进行扩容。

但假若要添加7个元素,初始容量参数也设置为7:new HashMap<>(7)

此时HashMap对象的初始容量仍会被设置为 8 ,但是当添加到第 6 个元素时,就会触发一次扩容。

因此,需要添加多少个元素,就将HashMap的容量设置为多少,不太合适

设置初始容量大小为initialCapacity=(需要存储的元素个数 / 负载因子) + 1,就是为了尽可能减少扩容的几率。如上需要添加 7 个元素时,initialCapacity = (7 / 0.75) + 1 = 10。

再经HashMap初始化处理后,实际容量被设置为 16,添加 7 个元素就不会发生resize操作。

推荐使用 guava 提供的集合类方法 Maps.newHashMapWithExpectedSize(expectedSize),该方法对 HashMap 的初始容量计算就是这个实现。

    public static <K, V> HashMap<K, V> newHashMapWithExpectedSize(int expectedSize) {
        return new HashMap(capacity(expectedSize));
    }

    static int capacity(int expectedSize) {
        if (expectedSize < 3) {
            CollectPreconditions.checkNonnegative(expectedSize, "expectedSize");
            return expectedSize + 1;
        } else {
            return expectedSize < 1073741824 ? (int)((float)expectedSize / 0.75F + 1.0F) : 2147483647;
        }
    }

假如你不关心 HashMap 扩容带来的性能影响,又不想被 Java 编码规约频繁提醒,也可使用 guava 提供的 Maps.newHashMap() 方法创建 HashMap 对象。

 

posted @ 2021-01-22 15:23  钟Sir_Zzz  阅读(537)  评论(0编辑  收藏  举报