HashMap in Depth
HashMap in Depth
A HashMap is the most-used implementation of the Map interface in Java. It stores data as key-value pairs, gives you O(1) average-case lookup by key, and is the right tool whenever you need to associate one thing with another — a username to a profile, a word to its frequency, a product id to its price.
The Map Interface
Before touching HashMap directly, understand what the Map interface promises. Unlike List or Set, a Map is not a Collection — it has its own type hierarchy. The contract says:
- Every key maps to exactly one value.
- Keys are unique; putting the same key twice replaces the old value.
- Values need not be unique — multiple keys can map to the same value.
- A key can map to
null, andnullitself is a valid key inHashMap.
Map<K,V> does not extend Collection<E>. You cannot pass a Map where a Collection is expected. You can, however, call map.values(), map.keySet(), or map.entrySet() to get collection views.
Creating a HashMap
Always declare with the interface type on the left so you can swap implementations later:
The diamond operator <> lets the compiler infer the type arguments. You can also seed a map at construction time in Java 9+:
Core Operations: put, get, remove
put(key, value) adds or replaces an entry and returns the previous value (or null if the key was absent). get(key) returns the value or null. remove(key) deletes the entry and returns the removed value.
stock.get("grapes") returns null. Assigning it to a primitive int (instead of Integer) causes a NullPointerException. Use getOrDefault or an explicit null check when the key might be absent.
Safer Gets: getOrDefault and computeIfAbsent
getOrDefault(key, fallback) returns the fallback instead of null when the key is missing. computeIfAbsent is the idiomatic way to build a value only when needed — perfect for grouping:
Key Uniqueness and equals / hashCode
HashMap uses a key's hashCode() to pick a bucket, then equals() to confirm identity. This means:
- Two objects that are
equals()must have the samehashCode(). - If you override
equals()in a custom class without overridinghashCode(), the map will silently create duplicate keys. - A key must never change while it is in the map — mutating a key after insertion breaks lookup.
Iterating Entries
There are three common ways to iterate a HashMap. The cleanest is entrySet(), which gives you both key and value together without a second lookup:
HashMap does not preserve insertion order. If you need predictable order use LinkedHashMap (insertion order) or TreeMap (sorted by key) — both covered in the next lesson.
Performance and Initial Capacity
Under the hood, HashMap stores entries in an array of buckets. When the number of entries exceeds capacity * loadFactor (default 0.75), it rehashes — allocating a larger array and redistributing all entries. Rehashing is O(n) and expensive. If you already know the approximate size, pass it at construction to avoid rehashing:
putIfAbsent and merge
Two more methods worth knowing before moving on:
putIfAbsent(key, value)— inserts only when the key is absent; returns the existing value otherwise.merge(key, value, remappingFn)— if absent, inserts the value; if present, applies the function to combine old and new values. Very handy for aggregation.
Summary
HashMap is the workhorse key-value store of the Java Collections Framework. Use put/get/remove for basic operations, getOrDefault and computeIfAbsent for safe access and building nested structures, and entrySet() with a for-each or forEach lambda for iteration. Remember that key uniqueness is enforced via equals() and hashCode() — always override both together in custom key classes.