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
關注公眾號「Java中文社群」查看更多 Java 總結性系列文章。