聊聊 HashMap 中的一个“坑”!

开发 前端
本文演示了 HashMap 作为返回类型时隐藏的一个小“坑”,因为 HashMap 本身是无序的,所以它会导致查询顺序和插入顺序不一致的问题。

[[433448]]

作者 | 王磊

来源 | Java中文社群(ID:javacn666) 

转载请联系授权(微信ID:GG_Stone)

最近公司新来了一个小伙伴,问了磊哥一个比较“奇怪”的问题,这个问题本身的难度并不大,但比较“隐蔽”,那究竟是什么问题呢?接下来我们一起来看。

起因

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

预期中的(正确)结果:

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

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

问题展示

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

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

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

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

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

原因分析

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

解决方案

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

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

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

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

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

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

LinkedHashMap 的魔力

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

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

总结

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

 

责任编辑:姜华 来源: Java中文社群
相关推荐

2021-08-14 09:48:02

ReentrantLock多线编程

2022-03-02 08:20:54

并发编程java后端开发

2022-03-09 09:43:20

并发编程Java

2020-03-26 17:00:53

HashMapputJava

2021-06-08 06:13:16

React开发开发技术

2022-03-22 06:33:49

Python内置模块函数

2022-04-08 08:48:16

线上事故日志订阅者

2018-12-29 08:15:28

Tomcat应用部署

2022-05-26 08:12:52

debugSpringFeign

2022-06-10 13:03:44

接口重试while

2022-11-08 08:35:53

架构微服务移动

2023-06-20 08:25:53

NESTED源码mybatis

2019-11-21 10:20:05

SQL错误用法数据库

2024-06-26 10:37:05

2020-11-16 11:24:00

Spring AOP数据库

2024-08-02 09:49:35

Spring流程Tomcat

2024-06-17 11:59:39

2022-04-27 07:21:06

HTTPAPI系统

2018-12-11 14:40:53

HashMapHashtableJava

2013-09-09 16:11:10

点赞
收藏

51CTO技术栈公众号