当前位置: 首页 > 科技观察

说说HashMap的一个“坑”!

时间:2023-03-18 21:17:24 科技观察

作者|王磊来源|Java中文社区(ID:javacn666)转载请联系授权(微信ID:GG_Stone)本身难度不大,但比较“隐蔽”,请问是什么问题呢?接下来,我们一起来看看吧。原因是公司系统最近新增了一个列表显示功能。函数本身并不难,但是遇到了一个很“奇怪”的问题。朋友在执行查询列表的时候,明明已经用orderby排序了,但是最后查询出来的数据还是乱七八糟的。预期(正确)结果:真实(意外)结果:那么问题出在哪里呢?问题展示为了展示方便,我将复杂的业务程序简化为如下代码:importjava.util.HashMap;publicclassApp{publicstaticvoidmain(String[]args){HashMapresult=getList();result.forEach((k,v)->{System.out.println(k+":"+v);});}//查询方法(简化版)publicstaticHashMapgetList(){HashMapresult=newHashMap<>();//最终返回的结果集//伪代码:从数据库查询后数据处理完毕,存储在for(inti=1;i<=5;i++){result.put("2022-10-"+i,"hellojava"+i);}returnresult;}}上面程序的执行结果如下:预期的结果应该是按时间顺序显示的,如下图:PS:上面的示例代码中,插入元素的顺序是有序的(从1到5),这在实际业务场景中是相当Orderby的。原因分析由于原始数据使用orderbysorting,所以原始数据肯定没问题,问题只会出现在返回集合HashMap上,然后我们把焦点放在HashMap上,瞬间醒悟,哦,原来如此.HashMap采用哈希的方式进行存储,因此存储和读取的顺序可能不一致。这也意味着HashMap是一个无序的集合,所以插入的顺序(或者orderby)会和最终显示的顺序不一致。解决方案经过上面的分析,我们成功的找到了问题所在,接下来就是制定相应的解决方案了。我想到了两个解决方案:有点麻烦但正确的解决方案:将返回的不确定数据类型HashMap改为For某种数据类型,比如List;一个更简单但不是最优的解决方案:将无序的HashMap更改为有序的LinkedHashMap。这种方案的好处是只需要改一个词就可以解决整个问题。第一种方案大家都懂,这里就不演示了。接下来,我们使用第二种方案来修改上面的问题。最终的实现代码如下:v)->{System.out.println(k+":"+v);});}//查询方法(简化版)publicstaticHashMapgetList(){HashMapresult=newLinkedHashMap<>();//最后返回的结果集//伪代码:从数据库中查询数据,然后对数据进行处理后,保存在for(inti=1;i<=5;i++){result.put("2022-10-"+i,"hellojava"+i);}returnresult;}}上面程序的执行结果如下:从上面的结果可以看出,当使用LinkedHashMap代替HashMap时,返回的订单可以与插入的订单一致。LinkedHashMap的神奇之处为什么HashMap是无序的,而LinkedHashMap是有序的?这要从两者的实施说起。LinkedHashMap是HashMap的一个子类,所以LinkedHashMap除了具有HashMap的所有特性外,还具有自己的特性。一些扩展属性,包括在LinkedHashMap中额外维护了一个双向链表,这个双向链表用来保存元素的(插入)顺序,这也是为什么LinkedHashMap可以做到访问顺序和插入顺序一致的原因。总结本文演示了使用HashMap作为返回类型时隐藏的一个小“坑”。因为HashMap本身是无序的,会造成查询顺序和插入顺序不一致的问题。对应的方案有两种:用确定的数据类型代替HashMap,比如List,或者用有序的LinkedHashMap代替无序的HashMap。