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中文社群」查看更多 Java 总结性系列文章。
HashMap 中的一个“坑”!的更多相关文章
- andriod8.1.0源码编译中的一个坑-package com.sun.javadoc does not exist
这里记录编译过程中的一个坑!!! 编译过程中出现了下面的报错 external/doclava/src/com/google/doclava/ClassInfo.java:20: error: pac ...
- 记前端状态管理库Akita中的一个坑
记状态管理库Akita中的一个坑 Akita是什么 Akita是一种基于RxJS的状态管理模式,它采用Flux中的多个数据存储和Redux中的不可变更新的思想,以及流数据的概念,来创建可观察的数据存储 ...
- Spring Boot 计划任务中的一个“坑”
计划任务功能在应用程序及其常见,使用Spring Boot的@Scheduled 注解可以很方便的定义一个计划任务.然而在实际开发过程当中还应该注意它的计划任务默认是放在容量为1个线程的线程池中执行, ...
- xcode中得一个坑
因项目需求变动,我必须在coredata中的WorkLogModel表中添加一个字段:抄送人.起初我给这个字段起名为copyPerson,一切准备就绪后,发现从数据库读取这个copyPerson时,第 ...
- PHP中的一个”坑“
说一个极有可能在工作中遇到的问题——foreach的引用 foreach $arr = range(1,3); //[1,2,3] foreach($arr as &$val) { } for ...
- 关于abp中使用的sweetalert对话框组件的confirm确认对话框中的一个坑
今天修改了一个功能,限制删除用户,在删除的时候不满足条件的时候提示用户原因,使用的sweet alert组件. abp框架前端集成了sweet alert 对http请求的error做了全局处理,我在 ...
- 在Java中==的一个坑
观察下面代码,输出结果是什么? public static void main(String[] args) { Integer p = 10000; Integer q = 10000; Syste ...
- mysql 线上not in查询中的一个坑
今天早上开发又过来说,怎么有个语句一直没有查询出结果,数据是有的呀,并发来了如下的sql(为了方法说明,表名及查询均做了修改): select * from t2 where t2.course no ...
- Makefile中的一个坑
问题描述:Makefile中,我想将一个变量的后缀全部进行替换,如将所有的.c后缀变成.d后缀 方法:$(CUR_SOURCE: .c = .d ) 说明:查阅相关资料,了解到上述这种语法就可以将所有 ...
随机推荐
- Linux系列(13) - CentOs 8 配置静态IP
step-1 vim etho的配置文件 [root#localhost ~]# vim /etc/sysconfig/network-scripts/ifcfg-eth0 step-2 新增修改以下 ...
- Shell系列(12)- 预定义变量(5)
预定义变量 作用 $? 常用:最后一次执行的命令的返回状态. 如果这个变量的值为0,证明上一个命令正确执行:如果这个变量的值为非0(具体是哪个数,由命令自己来决定),则证明上一个命令执行不正确了 $$ ...
- Web爬虫|入门实战之糗事百科(附源码)
coding by real mind writing by genuine heart 解析 任务背景:https://www.qiushibaike.com/hot/ 窥探网页细节:观察每一页 ...
- django class类即视图类添加装饰器的几种方法
根据别人发布整理,个人爱好收集(原文:https://blog.csdn.net/mydistance/article/details/83958655 ) 第一种:定义函数装饰器,在函数,类中使用函 ...
- Ubuntu学习之alias命令
Ubuntu学习之alias命令 1.1 alias功能介绍 当我们经常需要在命令窗键入复杂冗长的命令时,alias就派上用场啦.alias允许用户为命令创建简单的名称或缩写,哪怕这个缩写只有一个字符 ...
- 解决Vue项目打包之后放到nginx下刷新就报错404的问题
最近跟着某机构的教学视频敲了一遍vue项目,但是在windows环境下部署的时候就懵逼了放到nginx下正常跑没问题,但是刷新之后就报404错误 前端项目构建vue 脚手架版本 是@vue/cli 4 ...
- 数据结构与算法——克鲁斯卡尔(Kruskal)算法
目录 应用场景-公交站问题 克鲁斯卡尔算法介绍 克鲁斯卡尔算法图解 克鲁斯卡尔算法分析 如何判断回路? 代码实现 无向图构建 克鲁斯卡尔算法实现 获取一个点的终点解释 应用场景-公交站问题 某城市新增 ...
- C++学习笔记:08 多态性
课程<C++语言程序设计进阶>清华大学 郑莉老师) 基本概念 多态性 具体的讲,在面向对象程序设计中,指同样的方法被不同对象执行时会有不同的执行效果. 多态的实现 绑定机制 绑定是将一个标 ...
- Edit Step Ladders - UVA 10029
题意 题目链接(Virtual Judge):Edit Step Ladders - UVA 10029 题意: 如果单词 \(x\) 能通过添加.删除或修改一个字母变换为单词 \(y\),则称单词 ...
- C#开发BIMFACE系列45 服务端API之创建离线数据包
BIMFACE二次开发系列目录 [已更新最新开发文章,点击查看详细] BIMFACE的常规应用方式有公有云与私有化部署两种方式,并且浏览模型或者图纸需要使用ViewToken,ViewToke ...