Java HashMap初始化大小设置多少合适

news2024/11/25 6:48:07

修改公司老代码的时候,发现阿里编码规约插件提示HashMap初始化时尽量指定初始值大小,因为设置合理的初始值可以提升性能:

 HashMap继承自AbstractMap类,实现了Map、Cloneable、java.io.Serializable接口是基于散列表实现的双列集合,它存储的是key-value键值对映射,每个key-value键值对也被称为一条Entry条目。其中的 key与 value,可以是任意的数据类型,其类型可以相同也可以不同。但一般情况下,key都是String类型,有时候也可以使用Integer类型;value可以是任何类型。并且在HashMap中,最多只能有一个记录的key为null,但可以有多个value的值为null。HashMap中这些键值对(Entry)会分散存储在一个数组当中,这个数组就是HashMap的主体。

HashMap的实例有两个影响其性能的参数:初始容量和装载因子。容量是哈希表中的桶数,初始容量就是创建哈希表时的容量。负载因子是一种度量方法,用来衡量在自动增加哈希表的容量之前,哈希表允许达到的满度。当哈希表中的条目数超过负载因子和当前容量的乘积时,哈希表将被重新哈希(即重新构建内部数据结构),这样哈希表的桶数大约是原来的两倍。

那么在使用HashMap时要求尽量指定初始值,该指定多少合适?(可以直接跳到后面看结论)

一般来说,初始值大小的设定应该根据实际需要进行设置。另外,也建议将初始值大小设置为2的幂次方,这样可以更好地利用HashMap的内部机制,提高程序的运行效率

如果不设置,默认值是16。

如我截图的代码,就存放2个变量,初始值设置2,但是设置2真的合理吗?

我们可以看一下HashMap的源码,看看它里面是怎么实现的。

不设置初始值的构造方法:

/**
 * Constructs an empty <tt>HashMap</tt> with the default initial capacity
 * (16) and the default load factor (0.75).
 */
public HashMap() {
    this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}

设置初始值的构造方法:

/**
 * Constructs an empty <tt>HashMap</tt> with the specified initial
 * capacity and the default load factor (0.75).
 *
 * @param  initialCapacity the initial capacity.
 * @throws IllegalArgumentException if the initial capacity is negative.
 */
public HashMap(int initialCapacity) {
    this(initialCapacity, DEFAULT_LOAD_FACTOR);
}

this方法的源码:

/**
 * Constructs an empty <tt>HashMap</tt> with the specified initial
 * capacity and load factor.
 *
 * @param  initialCapacity the initial capacity
 * @param  loadFactor      the load factor
 * @throws IllegalArgumentException if the initial capacity is negative
 *         or the load factor is nonpositive
 */
public HashMap(int initialCapacity, float loadFactor) {
    if (initialCapacity < 0)
        throw new IllegalArgumentException("Illegal initial capacity: " +
                                           initialCapacity);
    if (initialCapacity > MAXIMUM_CAPACITY)
        initialCapacity = MAXIMUM_CAPACITY;
    if (loadFactor <= 0 || Float.isNaN(loadFactor))
        throw new IllegalArgumentException("Illegal load factor: " +
                                           loadFactor);
    this.loadFactor = loadFactor;
    this.threshold = tableSizeFor(initialCapacity);
}

里面的变量和方法,,我加了一些翻译说明:

/**
 * The next size value at which to resize (capacity * load factor).
 * 翻译:用于调整大小的下一次大小值(容量*负载因子)
 * @serial
 */
// (The javadoc description is true upon serialization.
// Additionally, if the table array has not been allocated, this
// field holds the initial array capacity, or zero signifying
// DEFAULT_INITIAL_CAPACITY.)
int threshold;

//默认大小为16
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16


/**
     * Returns a power of two size for the given target capacity.(翻译:返回给定目标容量的大小为2的幂)
     * 这段代码是一个名为 tableSizeFor 的静态方法,它接受一个整数参数 cap,并返回一个整数值。该方法的作用是计算并返回一个用于散列表(hash table)的合适的大小。
     *
     * 具体来说,该方法首先将 cap 减去 1,然后使用位运算符将结果向右移动,并按位或运算,以清除最低位的 1。
     * 这个过程会重复 5 次,每次向右移动的位数为 1、2、4、8 和 16。最后,如果计算出的值小于 0,则返回 1;
     * 如果计算出的值大于等于 MAXIMUM_CAPACITY,则返回 MAXIMUM_CAPACITY;否则返回计算出的值加 1。
     *
     * 这个方法的设计目的是为了在散列表中获得更好的负载因子(load factor),从而减少哈希冲突(hash collision)的概率。
     * 负载因子是指散列表中元素的数量与散列表大小的比率。较小的负载因子意味着每个桶(bucket)中存储的元素较少,从而减少了哈希冲突的概率。
     * 但是,较小的负载因子也会导致散列表的空间利用率较低。因此,选择合适的散列表大小非常重要。
     * @param cap
     * @return
     */
    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;
    }

上面的源码可以看出threshold是个阈值,它的计算是根据tableSizeFor方法来的(根据设置的初始值计算的),到达这个阈值就会触发扩容,扩容是会影响性能的。

再看一下putMapEntries方法的源码,看注释的意思是实现了Map.putAll和Map构造函数:

/**
 * Implements Map.putAll and Map constructor.
 *
 * @param m the map
 * @param evict false when initially constructing this map, else
 * true (relayed to method afterNodeInsertion).
 */
final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) {
    int s = m.size();
    if (s > 0) {
        if (table == null) { // pre-size
            float ft = ((float)s / loadFactor) + 1.0F;
            int t = ((ft < (float)MAXIMUM_CAPACITY) ?
                     (int)ft : MAXIMUM_CAPACITY);
            if (t > threshold)
                threshold = tableSizeFor(t);
        }
        else if (s > threshold)
            resize();
        for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {
            K key = e.getKey();
            V value = e.getValue();
            putVal(hash(key), key, value, false, evict);
        }
    }
}

这里面“ float ft = ((float)s / loadFactor) + 1.0F;”就是我们初始值的大小计算方法。

有兴趣的可以看下HashMap源码研究一下。

结论:默认不设置初始值大小,HashMap使用的是默认大小,值为16,如果要指定大小可以根据“存储数据的个数/0.75+1”计算出的结果作为初始值。

最后说明一下上面我的截图代码的问题,设置2是否合理?答案是不合理,根据计算公式得出,设置3是比较合理的。

原因是设置为2,刚好会触发扩容,造成完全没有必要的性能浪费。

参考以下代码,设置为2:

Map<String, String> map = new HashMap<>(2);
map.put("startTime", "");
getMapLength(map);
map.put("endTime", "");
getMapLength(map);

结果为:说明进行了扩容

设置为3:

Map<String, String> map = new HashMap<>(3);
map.put("startTime", "");
getMapLength(map);
map.put("endTime", "");
getMapLength(map);

结果为:没有进行扩容

打印Length方法:

/**
     * 打印Length
     * @param map
     * @throws Exception
     */
    static void getMapLength(Map<String, String> map) throws Exception {
        Field field = HashMap.class.getDeclaredField("table");
        field.setAccessible(true);
        Object[] elementData = (Object[]) field.get(map);
        System.out.println(elementData == null ? 0 : elementData.length);
    }

PS:关于是否设置初始值影响性能、初始值设置的合理与否影响性能,可以通过测试代码测一下,看看初始化的时间间隔。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/624159.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Prompt 工程指南(三)—— 高级技术篇之零样本和少样本提示

到目前为止&#xff0c;显而易见的是&#xff0c;改进提示有助于在不同任务上获得更好的结果。这就是提示工程背后的理念和目标。 虽然上篇教程介绍的基本示例已经很有趣&#xff0c;但在接下来的几篇教程中&#xff0c;我们将介绍更高级的 Prompt 提示工程技巧&#xff0c;使…

LabVIEW编程开发PCB测试仪

LabVIEW编程开发PCB测试仪 使用PXI和LabVIEW的PCB钉床测试仪 用于PCB&#xff08;印刷电路板&#xff09;的钉床测试仪&#xff0c;使用PXI和LabVIEW。一家电子制造公司需要测试仪来测试他们的PCB产品。钉床测试仪是一种具有连接到电路板上各个测试点的引脚的测试。电路板需要…

【大数据学习篇12】在linux上安装jupyter

下面介绍在liunx怎么安装jupyter&#xff0c;一步到位介绍。 1、安装Anaconda3 1.1 自己选择一个位置下载 wget https://repo.continuum.io/archive/Anaconda3-5.0.1-Linux-x86_64.sh1.2 进入自己的安装目录&#xff0c;安装anaconda bash Anaconda3-5.2.0-Linux-x86_64.sh一…

小程序模板语法样式与页面配置

文章和代码已经归档至【Github仓库&#xff1a;https://github.com/timerring/front-end-tutorial 】或者公众号【AIShareLab】回复 小程序 也可获取。 文章目录 小程序模板与配置WXML 模板语法数据绑定事件绑定小程序中常用的事件事件对象的属性列表target 和 currentTarget 的…

spark入门 高可用部署HA(五)

一、standalone基于修改部署 https://blog.csdn.net/weixin_43205308/article/details/131070277?spm1001.2014.3001.5501 二、安装ZOOKEEPER zookeeper 安装下载与集群 三、修改conf下的spark-env.sh vim conf/spark-env.sh注释以下内容&#xff08;根据自己环境修改&am…

备战金九银十:大厂面试官必问MySQL连环炮全梳理,你扛得住嘛?

最近后台好多小伙伴发私信咨询阿Q&#xff0c;问马上就是金九银十的面试黄金期了&#xff0c;该如何在三个月内突击一下&#xff0c;以便更好地通过面试呢&#xff1f; 阿Q的想法就是需要对自己掌握的知识进行归纳整理&#xff0c;系统的、分类的去复习相关的知识点。这样也能…

公司新来了个00后测开,上来一顿操作给我秀麻了.....

开年公司新来了个同事&#xff0c;听说大学是学的广告专业&#xff0c;因为喜欢IT行业就找了个培训班&#xff0c;后来在一家小公司实习半年&#xff0c;现在跳槽来我们公司。来了之后把现有项目的性能优化了一遍&#xff0c;服务器缩减一半&#xff0c;性能反而提升4倍!给公司…

提升效率:P4VFS让虚拟文件同步更迅速、更简单

虚拟文件同步&#xff08;Virtual File Sync&#xff09;是一个备受期待的功能集&#xff0c;能够显著缩短Perforce Helix Core用户的同步时间。本篇文件将解释什么是虚拟文件同步&#xff0c;如何设置它以及如何使用它。 什么是虚拟文件同步&#xff1f; 虚拟文件同步是一项…

配置Wildfly的JDBC驱动程序

1、环境 windows10、Wildfly26.1.3、JDK8.0、mysql8.0 2、配置方式 配置Wildfly的JDBC驱动一般有两种方式 1️⃣、以module的方式安装&#xff1b; 2️⃣、以应用deploy的程序包方式安装&#xff1b; 以module方式安装&#xff0c;是把驱动置于应用服务器中&#xff1b;以…

Ubuntu 20.04 Apache2 增加不同端口站点

概述 Apache HTTP Server&#xff08;简称Apache&#xff09;是Apache软件基金会的一个开放源码的网页服务器软件&#xff0c;可以在大多数电脑操作系统中运行。由于其跨平台和安全性[注 1]&#xff0c;被广泛使用&#xff0c;是最流行的Web服务器软件之一。它快速、可靠并且可…

ROS:move_base路径规划介绍、更换全局路径规划算法(A star、Dijkstra、DWA,测试当前是哪种算法,效果展示图)

前提&#xff1a;需要安装navigation包&#xff0c;才可以运行move_base。 一.move_base路径规划包内容 二.更换全局路径规划算法&#xff08;A*、Dijkstra、DWA&#xff09; A*、Dijkstra属于全局路径规划、DWA属于局部路径规划。 1、move_base.launch move_base.launch文…

开源 AI 面临的挑战

译者&#xff1a;明明如月 人工智能的代价 尽管我坚信开源人工智能将继续蓬勃发展&#xff0c;但我也认为未来几年企业和政府将越来越有动机限制对新型神经网络架构和技术的应用。本文旨在预测并概述可能在本十年发生的潜在颠覆性变革&#xff0c;并提出一些想法和解决方案&a…

玩转css逐帧动画,努力成为更优质的Ikun~

&#x1f389; 一、前言 css3的animation想必大家都知道吧&#xff0c;那 steps 逐帧动画你知道吗&#xff1f;对于我来说&#xff0c;实际工作及练习中也很少用到这种跳跃式变化的动画&#xff0c;而它start和end的解释又比较“不说人话”&#xff0c;以前用到steps动画的时候…

FL Studio21水果软件各个版本功能区别对比

作为音乐人&#xff0c;在电脑上进行编曲&#xff0c;混音&#xff0c;合成是家常便饭&#xff0c;而市面上大家常用的音乐编曲制作软件很多&#xff0c;小编在这里就给大家做一个推荐。 大家常听到的音乐编曲制作软件大多是Cubase、Nuendo、Pro Tools、 SONAR等等&#xff0c…

Qt中QFile类读取ansi编码格式txt文件,在QTextEdit控件中显示乱码

系列文章目录 文章目录 系列文章目录前言一、依然无法解决乱码问题二、解决办法1.方法一&#xff1a;使用QString的fromLocal8Bit()函数2.读取utf-8编码格式的文件 总结 前言 使用Qt中的QFile类读取ANSI编码格式的文本文件&#xff0c;并在QTextEdit控件中显示乱码&#xff0c…

适配器模式的运用

文章目录 一、适配器模式的运用1.1 介绍1.2 适配器模式结构1.3 类适配器模式1.3.1 类适配器模式类图1.3.2 代码 1.4 对象适配器模式1.4.1 对象适配器模式类图1.4.2 代码 1.5 应用场景1.6 JDK源码解析1.6.1 字节流到字符流的转换类图1.6.2 部分源码分析1.6.3 总结 一、适配器模式…

MyBatis的使用、Spring AOP、Spring事务

一、MyBatis 的使用 1、环境配置 1.1、建库建表 -- 创建数据库 drop database if exists mycnblog; create database mycnblog DEFAULT CHARACTER SET utf8mb4;-- 使⽤数据数据 use mycnblog;-- 创建表[⽤户表] drop table if exists userinfo; create table userinfo(id in…

智能算法终极大比拼,以CEC2017测试函数为例,十种智能算法直接打包带走,不含任何套路!

包含人工蜂群(ABC)、灰狼(GWO)、差分进化(DE)、粒子群(PSO)、麻雀优化(SSA)、蜣螂优化(DBO)、白鲸优化(BWO)、遗传算法(GA)、粒子群算法(PSO)&#xff0c;基于反向动态学习的差分进化算法&#xff0c;共十种算法&#xff0c;直接一文全部搞定&#xff01; 还是老规矩&#xff…

Android MaterialComponents主题下Button设置background无效

问题描述 使用的主题代码如下图&#xff1a; <!-- Base application theme. --><style name"Base.Theme.MyApplication" parent"Theme.Material3.DayNight.NoActionBar"><!-- Customize your light theme here. --><!-- <item na…

JAVA面向对象(二)

第二章 方法与方法重载 目录 第二章 方法与方法重载 带参方法的使用 构造方法 构造方法重载 成员变量和局部变量 总结 内容仅供学习交流&#xff0c;如有问题请留言或私信&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; 有空您就点点赞 带参方法的使用…