乐趣区

关于后端: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 的)程序,与最终展现的程序不统一。

解决方案

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

  1. 略微麻烦一点但正确的解决方案:将返回的不确定数据类型 HashMap 改为确定的数据类型,比方 List<T>;
  2. 简略一点但并不是最优的解决方案:将无序的 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<T>,或者应用有序的 LinkedHashMap 来代替无序的 HashMap。

关注公众号「Java 中文社群」查看更多 Java 总结性系列文章。

退出移动版