AI helped me avoid a big pit in calculating the hash value of Map

Author : Mingming Ruyue senior, CSDN blog expert, senior Java engineer of Ant Group, author of "Performance Optimization Methodology", "Unlocking Big Factory Thinking: Analysis of "Alibaba Java Development Manual", "Re-learning Classics: Exclusive Analysis of "EffectiveJava"" Columnist.

Recommended popular articles :

1. Background

A business scenario needs to calculate the hash value of the Map as a component of the cache key. The idea is to convert the Map into a string, and then get the Hash value of the string.
However, there is a big pit here, that is, the order of the Entry in the Map, that is, only the order of the Key is different but the hash value should be the same when the value is the same.
If you use AI, you will probably notice this problem. If you write it yourself, it is easy to ignore this problem.

2. Problem recurrence

Construct two Maps with equivalent "key values", and find that their hash values ​​are different.

import com.google.common.base.Charsets;
import com.google.common.hash.Hashing;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

public class Main {
    
    
    public static void main(String[] args) {
    
    
        Map<String, String> map1 = new LinkedHashMap<>();
        map1.put("key1", "value1");
        map1.put("key2", "value2");

        Map<String, String> map2 = new LinkedHashMap<>();
        map2.put("key2", "value2");
        map2.put("key1", "value1");

        String mapString1 = map1.entrySet()
                .stream()
                .map(e -> e.getKey() + "=" + e.getValue())
                .collect(Collectors.joining(", "));

        String mapString2 = map2.entrySet()
                .stream()
                .map(e -> e.getKey() + "=" + e.getValue())
                .collect(Collectors.joining(", "));

        String hash1 = Hashing.sha256()
                .hashString(mapString1, Charsets.UTF_8)
                .toString();

        String hash2 = Hashing.sha256()
                .hashString(mapString2, Charsets.UTF_8)
                .toString();

        System.out.println("The hash of the first map is: " + hash1);
        System.out.println("The hash of the second map is: " + hash2);
        System.out.println(hash1.equals(hash2));
    }
}

Output result:

The hash of the first map is: 500ccf8d28b6857c91a01a1e6d751e89d3872af97a8079cecd1dce0497ab084d
The hash of the second map is: d7d67e36f33ebf3f51e1d0c6e016a17a2d839e897951bb98fa5cd190a135b331
false

Some students may say that what you use here will LinkedHashMapof course have problems.
But the problem is that usually when we define an interface, the parameter is of Map type, and the two "key values" are equivalent, and the order of their Entry may not be equal.

Three, the solution

Sort the strings after the Entry or map, and ensure that the strings concatenated before the hash of two Maps with equivalent "key values" are the same.

import com.google.common.base.Charsets;
import com.google.common.hash.Hashing;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.stream.Collectors;

public class MapHashDemo {
    
    
    public static void main(String[] args) {
    
    
        Map<String, String> map1 = new LinkedHashMap<>();
        map1.put("key1", "value1");
        map1.put("key2", "value2");

        Map<String, String> map2 = new LinkedHashMap<>();
        map2.put("key2", "value2");
        map2.put("key1", "value1");


        String hash1 = getSha256(map1);

        String hash2 = getSha256(map2);

        System.out.println("The hash of the first map is: " + hash1);
        System.out.println("The hash of the second map is: " + hash2);
        System.out.println(hash1.equals(hash2));
    }


    private static String getSha256(Map<String, String> map) {
    
    
        String mapString1 = map.entrySet()
                .stream()
                .map(e -> e.getKey() + "=" + e.getValue())
                .sorted()
                .collect(Collectors.joining(", "));

        return Hashing.sha256()
                .hashString(mapString1, Charsets.UTF_8)
                .toString();
    }
}

The hash of the first map is: 500ccf8d28b6857c91a01a1e6d751e89d3872af97a8079cecd1dce0497ab084d
The hash of the second map is: 500ccf8d28b6857c91a01a1e6d751e89d3872af97a8079cecd1dce0497ab084d
true

In this way, even if the order of the Entry in the Map is inconsistent, the calculated sha256 hash value is also the same.

3. AI assistance

In addition, I once again recommend that you try to use AI tools such as ChatGPT and New Bing in your daily work and study. Such simple codes allow them to give demos, and the demos they give have a high probability of giving the correct code .

How to use com.google.common.hash.Hashing to calculate the hash value of a Map?

The answer given by ChatGPT:


com.google.common.hash.Hashingis a class in the Google Guava library that provides a series of hash functions.
To calculate the hash value of a Map, we can first convert the key and value of the Map into strings, and then use Hashing's hash function for calculation.
Here is a simple example, assuming we have a Map<String, String> :

import com.google.common.base.Charsets;
import com.google.common.hash.Hashing;
import java.util.Map;

public class Main {
    
    
    public static void main(String[] args) {
    
    
        Map<String, String> map = new HashMap<>();
        map.put("key1", "value1");
        map.put("key2", "value2");

        String mapString = map.entrySet()
                              .stream()
                              .map(e -> e.getKey() + "=" + e.getValue())
                              .sorted()
                              .collect(Collectors.joining(", "));

        String hash = Hashing.sha256()
                             .hashString(mapString, Charsets.UTF_8)
                             .toString();

        System.out.println("The hash of the map is: " + hash);
    }
}

In this example, we first convert each item (key and value) of the Map into a string in the format of "key=value", and then sort and concatenate these strings with commas to generate a total string. Finally, we calculate the hash value of this string using Guava's Hashing.sha256() function.

**It should be noted that since the elements of Map have no fixed order, we need to sort them when generating strings to ensure that the same Map can get the same hash value. **At the same time, when using the hash function, you need to choose an appropriate character set, here we choose UTF-8.

In addition, pay attention to the problem of hash collisions. Although for most cases, the probability of hash collisions is very small, it is still possible in theory. Therefore, when using hash values, it is necessary to judge whether this potential conflict risk is acceptable according to the specific situation.

Four. Summary

You need to pay special attention to this issue when calculating the hash value of the Map as the cache key.
It is recommended that you use some simple code examples and some verification codes in daily development. It is recommended that you let AI write for us first, and sometimes there will be unexpected gains.


Creation is not easy. If this article is helpful to you, please like, bookmark and pay attention. Your support and encouragement are the biggest motivation for my creation.
insert image description here

Welcome to join my Knowledge Planet, Knowledge Planet ID: 15165241 to communicate and learn together.
https://t.zsxq.com/Z3bAiea is marked from CSDN when applying.

Guess you like

Origin blog.csdn.net/w605283073/article/details/130663235