<code>HashMap</code> in Java β Key/Value Lookup in O(1)
HashMap is Java's main keyβvalue lookup table. Average-case O(1) for get, put, containsKey and remove. Iteration order is not guaranteed and has changed between JDK versions β if order matters, use LinkedHashMap or TreeMap.
Basics
var votes = new HashMap<String, Integer>();
votes.put("Alice", 1);
votes.put("Bob", 2);
Integer a = votes.get("Alice"); // 1
Integer z = votes.get("unknown"); // null
int v = votes.getOrDefault("unknown", 0); // 0 β no null
votes.containsKey("Alice"); // true
votes.remove("Bob");
votes.size();
Modern helpers (Java 8+)
// Increment-or-create
votes.merge("Alice", 1, Integer::sum);
// Lazy init of a value
var index = new HashMap<String, List<User>>();
index.computeIfAbsent(user.city(), k -> new ArrayList<>()).add(user);
// Conditional update
votes.replace("Alice", 5); // only if key exists
votes.putIfAbsent("Carol", 0); // only if absent
How it works
put(k, v)computesk.hashCode(), mixes it, and mods into a bucket index.- The bucket holds a linked list (or a balanced tree for large buckets since Java 8).
- On collision, the list/tree is scanned with
equals(). - If the map's size exceeds capacity Γ load factor (default 0.75), the buckets are doubled and everything is rehashed.
The equals/hashCode contract
Any custom key must override equals and hashCode consistently:
// β Broken custom key β no hashCode override
class Bad {
final int id;
Bad(int id) { this.id = id; }
public boolean equals(Object o) {
return o instanceof Bad b && b.id == id;
}
// hashCode from Object β same-id objects get different hashes
}
var m = new HashMap<Bad, String>();
m.put(new Bad(1), "hi");
m.get(new Bad(1)); // null β ended up in a different bucket
Records give you both for free. Use a record or Lombok's @EqualsAndHashCode.
Mutable keys β don't
var key = new StringBuilder("a");
map.put(key, 1);
key.append("b"); // hashCode changed
map.get(key); // null β lookup goes to the wrong bucket
Iteration
for (var e : map.entrySet()) {
System.out.println(e.getKey() + "=" + e.getValue());
}
map.forEach((k, v) -> System.out.println(k + "=" + v));
// By entries, sorted by key
map.entrySet().stream()
.sorted(Map.Entry.comparingByKey())
.forEach(e -> System.out.println(e.getKey() + "=" + e.getValue()));
HashMap vs alternatives
| Need | Pick |
|---|---|
| Default map | HashMap |
| Insertion-order iteration | LinkedHashMap |
| Sorted by key | TreeMap |
| Thread-safe | ConcurrentHashMap |
| Small, immutable, known at build time | Map.of(...) |
| Immutable copy | Map.copyOf(other) |
Common mistakes
- Using
HashMapacross threads β corruption, infinite loops. UseConcurrentHashMap. - Custom key without
hashCodeβ silent data loss. Use records. - Assuming insertion order β use
LinkedHashMap. get()returning null β easy to NPE on auto-unbox. UsegetOrDefault.
Related
Pillar: Java collections. Siblings: LinkedHashMap, TreeMap, equals & hashCode.