Question 27 · Section 13

Can you use immutable objects as keys in HashMap?

String computes hashCode once and caches it:

Language versions: English Russian Ukrainian

Junior Level

Not just possible, but highly recommended! Immutable objects are ideal keys for HashMap.

Map<String, Integer> ages = new HashMap<>();
ages.put("Ivan", 25);  // String — immutable
ages.put("Ivan", 30);  // Update by the same key

System.out.println(ages.get("Ivan")); // 30

Why this is good

  • hashCode() doesn’t change — object is always in the correct bucket
  • equals() works stably
  • No need to worry about the key getting “lost”

Best keys

  • String — most popular
  • Integer, Long — primitive wrappers
  • LocalDate, UUID — stable identifiers
  • Record — composite keys from multiple fields

Middle Level

How HashMap works with keys

  1. put(key, value)key.hashCode() is computed → bucket is determined
  2. get(key)key.hashCode() is computed again → searched in the same bucket
  3. If hashCode() changed — the key is “lost” in a different bucket

Immutable objects cache hashCode

String computes hashCode once and caches it:

// Inside String
private int hash; // 0 by default
public int hashCode() {
    if (hash == 0 && value.length > 0) {
        hash = ...; // computed once
    }
    return hash;
}

Problem with mutable keys

List<String> key = new ArrayList<>(List.of("A"));
map.put(key, 42);
key.add("B");           // changed the key!
map.get(key);           // null — hashCode changed

The object is physically in the bucket, but get searches elsewhere.

Important: equals and hashCode must use the same set of fields. If hashCode uses id but equals uses id + name — two objects with the same id but different names end up in the same bucket but won’t be equal.


Senior Level

Ideal key for HashMap

public record CompositeKey(String type, Long id) {} // automatically final, equals, hashCode

Map<CompositeKey, Entity> map = new HashMap<>();
map.put(new CompositeKey("user", 1L), user);

Strategy if the key must be mutable

  1. Use an identifier: Long id instead of the object itself
  2. Remove → modify → re-add:
    map.remove(key);
    key.changeSomething();
    map.put(key, value);
    
  3. IdentityHashMap — compares by ==, not by equals()/hashCode()

hashCode for composite keys

Record generates hashCode via Objects.hashCode for each field. On collisions, HashMap builds a tree (O(log n) instead of O(n)). For composite keys, combine hashCode of all significant fields.

Summary for Senior

  • Immutable keys guarantee determinism of hash collections
  • Prevent hard-to-find bugs and memory leaks
  • Record — ideal choice for composite keys
  • Design collection keys as immutable entities
  • Cached hashCode — additional optimization

Interview Cheat Sheet

Must know:

  • Immutable objects are IDEAL keys: stable hashCode, no risk of loss in bucket
  • String, Integer, LocalDate, Record — best keys
  • String caches hashCode — computed once, speeds up repeated lookups
  • Record generates equals/hashCode via Objects.hashCode for each field
  • Mutable key = lost object: hashCode changed, get searches in a different bucket
  • On collisions, HashMap builds a tree — O(log n) instead of O(n)

Frequent follow-up questions:

  • Why is a mutable key dangerous? — hashCode changes → object gets “lost” → logical leak
  • Record as a key? — Ideal: automatically final, equals, hashCode across all fields
  • If the key must be mutable? — IdentityHashMap (comparison by ==) or remove → mutate → put
  • Should equals and hashCode match? — Yes, use the same set of fields

Red flags (do NOT say):

  • “Mutable key in HashMap is fine” — object becomes unreachable
  • “hashCode doesn’t need caching” — for immutable objects it’s an optimization
  • “ArrayList as a key is a good idea” — it’s mutable, hashCode will change
  • “IdentityHashMap solves all problems” — compares by ==, not equals — a specific use case

Related topics:

  • [[22. What are the advantages of immutable objects for caching]]
  • [[28. What happens if you modify a mutable key in HashMap]]
  • [[20. What is Record and how does it help create immutable classes]]
  • [[4. Why is String class immutable]]