A "pit" in HashMap!

Recently, a new partner of the company asked brother Lei a "strange" question. The problem itself is not difficult, but it is "hidden". What is the problem? Next, let's take a look.

cause

Recently, the company's system wants to add a new list display function. The function itself is not difficult, but it has encountered a very "strange" problem. When the small partner executes the query list, he has used order by to sort, but the final queried data is still messy.

Expected (correct) results:

Realistic (unexpected) results:

So where is the problem?

Problem display

To facilitate the presentation, I simplified the complex business process into the following code:

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);
        });
    }

    // Query method (simplified version)
    public static HashMap<String, Object> getList() {
        HashMap<String, Object> result = new HashMap<>(); // Final returned result set
        // Pseudo code: after querying the data from the database and processing the data, it is saved to the database
        for (int i = 1; i <= 5; i++) {
            result.put("2022-10-" + i, "hello java" + i);
        }
        return result;
    }
}

The results of the above procedures are as follows:

The expected results should be displayed in chronological order, as shown in the figure below:

PS: in the above example code, the order of inserting elements is orderly (from 1 to 5), which is equivalent to order by in the actual business scenario.

Cause analysis

Since the original data uses order by sorting, the original data must be OK. The problem will only appear on the return set HashMap. Then we will focus on the HashMap and wake up instantly. Oh, I see. HashMap is stored in hash mode, so the order of storage and reading may be inconsistent. This also means that HashMap is an unordered collection, so the order of insertion (or order by) will be inconsistent with the order of final display.

Solution

After the above analysis, we have successfully found the problem, and then we will formulate corresponding solutions. I think of two solutions:

  1. A slightly troublesome but correct solution: change the returned uncertain data type HashMap to the determined data type, such as list < T >;
  2. Simple but not the best solution: change the disordered HashMap to the ordered LinkedHashMap. The advantage of this solution is that you can solve the whole problem by changing only one word.

The first solution is understood by everyone and will not be demonstrated here. Next, let's use the second solution to transform the above problems. The final implementation code is as follows:

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);
        });
    }

    // Query method (simplified version)
    public static HashMap<String, Object> getList() {
        HashMap<String, Object> result = new LinkedHashMap<>(); // Final returned result set
        // Pseudo code: after querying the data from the database and processing the data, it is saved to the database
        for (int i = 1; i <= 5; i++) {
            result.put("2022-10-" + i, "hello java" + i);
        }
        return result;
    }
}

The results of the above procedures are as follows:

As can be seen from the above results, when LinkedHashMap is used instead of HashMap, the return order can be consistent with the insertion order.

The magic of LinkedHashMap

Why is HashMap unordered and LinkedHashMap ordered?

This starts with the implementation of the two. LinkedHashMap belongs to the subclass of HashMap. Therefore, LinkedHashMap not only has all the features of HashMap, but also has some extended properties, including a two-way linked list maintained in LinkedHashMap, which is used to save the (insertion) order of elements, This is why LinkedHashMap can achieve the same access order and insertion order.

summary

This article demonstrates a small "pit" hidden when HashMap is used as a return type. Because HashMap itself is disordered, it will lead to the inconsistency between query order and insertion order. There are two corresponding solutions: use the determined data type to replace HashMap, such as list < T >, or use the ordered LinkedHashMap to replace the disordered HashMap.

Pay attention to the Chinese community of official account "Java Chinese community" to see more Java summary articles.

Tags: Back-end

Posted on Thu, 04 Nov 2021 13:44:08 -0400 by beebum