Java中HashMap 中的一个坑

 更新时间:2022年05月19日 10:07:12   作者:​ Java中文社群   ​  
这篇文章主要介绍了Java中HashMap 中的一个坑,文章围绕主题展开详细的内容介绍,具有一定的参考价价值,需要的小伙伴可以参考一下

前言

最近公司的系统要增加一个新的列表展示功能,功能本身难度并不大,但遇到了一个很“奇怪”的问题。小伙伴在执行查询列表时,明明已经使用了 order by 进行排序了,但最终查询出来的数据却还是乱的。

预期中的(正确)结果: 

 现实中的(非预期)结果: 

 那到底是哪里出现了问题呢?

问题展示

为了方便展示,我把复杂的业务程序简化成了以下代码:

import java.util.HashMap;
public class App {
    public static void main(String[] args) {
        HashMap<String, Object> result = getList();
        result.forEach((k, v) -> {
            System.out.println(k + ":" + v);
        });
    }
    // 查询方法(简化版)
    public static HashMap<String, Object> getList() {
        HashMap<String, Object> result = new HashMap<>(); // 最终返回的结果集
        // 伪代码:从数据库中查询出了数据,然后对数据进行处理之后,存到了
        for (int i = 1; i <= 5; i++) {
            result.put("2022-10-" + i, "hello java" + i);
        }
        return result;
    }
}

以上程序的执行结果如下: 

预期的结果应该是按时间的先后顺序展示的,如下图所示: 

PS:以上示例代码中,插入元素的顺序是有序的(从 1 到 5),相当于实际业务场景中的 order by。

原因分析

既然原数据使用了 order by 排序,那么原数据肯定是没问题的,那问题就只会出现在返回集 HashMap 上,然后我们再把焦点放到 HashMap 上, 瞬间醒悟,哦,原来如此。HashMap 使用的是哈希方式进行存储的,因此存入和读取的顺序可能是不一致的,这也说 HashMap 是无序的集合,所以会导致插入的(或 order by 的)顺序,与最终展示的顺序不一致。

解决方案

经过上面的分析我们顺利找到了问题,那接下来就是制定相应的解决方案了,我想到的解决方案有两个:

  • 稍微麻烦一点但正确的解决方案:将返回的不确定数据类型 HashMap 改为确定的数据类型,比如 List;
  • 简单一点但并不是最优的解决方案:将无序的 HashMap 改为有序的 LinkedHashMap,此方案的优点是,只需要改动一个单词就可以解决整个问题了。

第一种解决方案大家都懂这里就不演示了,接下来咱们使用第二种解决方案将上面的问题改造一下,

最终的实现代码如下:

import java.util.HashMap;
import java.util.LinkedHashMap;
public class App {
    public static void main(String[] args) {
        HashMap<String, Object> result = getList();
        result.forEach((k, v) -> {
            System.out.println(k + ":" + v);
        });
    }

    // 查询方法(简化版)
    public static HashMap<String, Object> getList() {
        HashMap<String, Object> result = new LinkedHashMap<>(); // 最终返回的结果集
        // 伪代码:从数据库中查询出了数据,然后对数据进行处理之后,存到了
        for (int i = 1; i <= 5; i++) {
            result.put("2022-10-" + i, "hello java" + i);
        }
        return result;
    }
}

以上程序的执行结果如下: 

 从上述结果可以看出,当使用 LinkedHashMap 替代了 HashMap 之后,返回的顺序就能和插入的顺序保持一致了。

LinkedHashMap 的魔力

为什么 HashMap 是无序的,而 LinkedHashMap 却是有序的呢?

这要从二者的实现说起了,LinkedHashMap 属于 HashMap 的子类,所以 LinkedHashMap 除了拥有 HashMap 的所有特性之后,还具备自身的一些扩展属性,其中就包括 LinkedHashMap 中额外维护了一个双向链表,这个双向链表就是用来保存元素的(插入)顺序的,这也是为什么 LinkedHashMap 可以实现访问顺序和插入顺序一致的原因了。

总结

本文演示了 HashMap 作为返回类型时隐藏的一个小“坑”,因为 HashMap 本身是无序的,所以它会导致查询顺序和插入顺序不一致的问题,对应的解决方案有两种:使用确定的数据类型来替代 HashMap,比如 List,或者使用有序的 LinkedHashMap 来替代无序的 HashMap。

到此这篇关于Java中HashMap 中的一个坑的文章就介绍到这了,更多相关Java HashMap 内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Spring Boot集成Java DSL的实现代码

    Spring Boot集成Java DSL的实现代码

    这篇文章主要介绍了Spring Boot集成Java DSL的实现代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-01-01
  • Java实现FIFO、LRU、LFU、OPT页面置换算法

    Java实现FIFO、LRU、LFU、OPT页面置换算法

    本文主要介绍了Java实现FIFO、LRU、LFU、OPT页面置换算法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-02-02
  • 使用jaxp进行dom解析_动力节点Java学院整理

    使用jaxp进行dom解析_动力节点Java学院整理

    这篇文章主要介绍了使用jaxp进行dom解析的相关资料,需要的朋友可以参考下
    2017-08-08
  • SpringBoot @CompentScan excludeFilters配置无效的解决方案

    SpringBoot @CompentScan excludeFilters配置无效的解决方案

    这篇文章主要介绍了SpringBoot @CompentScan excludeFilters配置无效的解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-11-11
  • JDK安装与配置超级详细教程(包含二个或多个JDK的同时安装)

    JDK安装与配置超级详细教程(包含二个或多个JDK的同时安装)

    这篇文章主要给大家介绍了关于JDK安装与配置(包含二个或多个JDK的同时安装)的相关资料,对于Java学习者来说,一台电脑拿到手肯定要配置JDK,但是对于新手来说还是容易出错,需要的朋友可以参考下
    2023-10-10
  • Java中super关键字介绍以及super()的使用

    Java中super关键字介绍以及super()的使用

    这几天看到类在继承时会用到this和super,这里就做了一点总结,下面这篇文章主要给大家介绍了关于Java中super关键字介绍以及super()使用的相关资料,需要的朋友可以参考下
    2022-01-01
  • Java中Synchronized锁的使用和原理详解

    Java中Synchronized锁的使用和原理详解

    这篇文章主要介绍了Java中Synchronized锁的使用和原理详解,synchronized是 Java 内置的关键字,它提供了一种独占的加锁方式,synchronized的获取和释放锁由JVM实现,用户不需要显示的释放锁,非常方便,需要的朋友可以参考下
    2023-07-07
  • 浅谈关于Mybatis的mapper-locations配置问题

    浅谈关于Mybatis的mapper-locations配置问题

    MyBatis 是一款优秀的半自动的ORM持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作,需要的朋友可以参考下
    2023-05-05
  • java一个接口多个实现类的调用方式

    java一个接口多个实现类的调用方式

    这篇文章主要给大家介绍了关于java一个接口多个实现类的调用方式的相关资料,经测试确认,当一个接口有多个实现时,调用时只会执行一个,有时候需要多个实现调用,需要的朋友可以参考下
    2023-09-09
  • Java实现酒店客房管理系统

    Java实现酒店客房管理系统

    这篇文章主要为大家详细介绍了Java实现酒店客房管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-02-02

最新评论