Broken hashCode in HashMap

How HashMap Uses Them

map.get(key)
   │ 1. key.hashCode() → choose bucket
   ▼
 bucket 0 │ bucket 1 │ bucket 2 ─► [k1=v1] ─► [k2=v2]   (linked list / tree)
                                  │ 2. key.equals(k?) → find the entry

If you override equals but not hashCode, two equal keys usually land in different buckets, so the map never finds the second one.

The Bug

Example

BadSku overrides only equals. The set keeps "duplicates" and lookups fail.

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Set<BadSku> bad = new HashSet<>();
        bad.add(new BadSku("PHN-01"));
        bad.add(new BadSku("PHN-01"));
        System.out.println("BadSku set size: " + bad.size() + "  (should be 1)");
        System.out.println("contains? " + bad.contains(new BadSku("PHN-01")));

        Set<GoodSku> good = new HashSet<>();
        good.add(new GoodSku("PHN-01"));
        good.add(new GoodSku("PHN-01"));
        System.out.println("GoodSku set size: " + good.size());
        System.out.println("contains? " + good.contains(new GoodSku("PHN-01")));
    }
}

class BadSku {
    final String code;
    BadSku(String code) { this.code = code; }
    @Override public boolean equals(Object o) { return o instanceof BadSku b && b.code.equals(code); }
    // hashCode() NOT overridden: identity hash, different for each object
}

record GoodSku(String code) {}

Output

BadSku set size: 2  (should be 1)
contains? false
GoodSku set size: 1
contains? true

Mutable Keys

Example

Changing a field used in hashCode after inserting the key "loses" the entry. Use immutable keys.

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Map<MutableKey, String> map = new HashMap<>();
        MutableKey key = new MutableKey("A");
        map.put(key, "order data");
        key.id = "B";                                  // hash changes
        System.out.println("get(key): " + map.get(key));
        System.out.println("size: " + map.size());
    }
}

class MutableKey {
    String id;
    MutableKey(String id) { this.id = id; }
    @Override public boolean equals(Object o) { return o instanceof MutableKey k && k.id.equals(id); }
    @Override public int hashCode() { return id.hashCode(); }
}

Output

get(key): null
size: 1