Stage 5: Collections compared, lesson 5 of 8

HashMap vs LinkedHashMap

Intermediate3 min read@since 8Code runs on your Java 25
Explain it forThe essentials plus production detail and pitfalls.

LinkedHashMap is a HashMap plus a doubly linked list running through all its entries. That list gives it a predictable iteration order:

  • Insertion order (the default): entries come out in the order they were first put. Re-putting an existing key doesn't move it.
  • Access order (new LinkedHashMap<>(16, 0.75f, true)): every get or put moves the entry to the end, so the first entry is always the least recently used. Combined with removeEldestEntry, that's an LRU cache in a few lines.

Everything else is HashMap: O(1) operations, one null key, not thread-safe. It costs a little more memory (two extra pointers per entry) and is slightly slower to change.

Use LinkedHashMap when order matters: JSON output that should keep field order, "recently viewed" lists, caches. Use HashMap when it doesn't.

Side by side

HashMapLinkedHashMap
Iteration orderUnpredictable (can change on resize)Insertion order, or access order
InternalsHash tableHash table + doubly linked list through entries
get / putO(1)O(1), slightly more work
MemoryLessTwo extra pointers per entry
IteratingVisits every bucket (proportional to capacity)Follows the list (proportional to size)
LRU cacheNoYes: access order + removeEldestEntry
Java 21 sequenced methodsNofirstEntry, lastEntry, pollFirstEntry, putFirst, reversed
Use it forOrder doesn't matterOrder matters, caches

Example

Java
Map<String, Integer> hash = new HashMap<>();
Map<String, Integer> linked = new LinkedHashMap<>();
for (String k : List.of("mango", "apple", "zebra")) { hash.put(k, 1); linked.put(k, 1); }
System.out.println(hash.keySet());     // [zebra, apple, mango]  order comes from the hash codes
System.out.println(linked.keySet());   // [mango, apple, zebra]  insertion order
An LRU cache in eight lines (LinkedHashMap is designed to be extended this way)
class LruCache<K, V> extends LinkedHashMap<K, V> {
    private final int max;
    LruCache(int max) { super(16, 0.75f, true); this.max = max; }   // true = access order

    @Override protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
        return size() > max;                                         // evict the least recently used
    }
}

LruCache<String, String> cache = new LruCache<>(2);
cache.put("a", "A"); cache.put("b", "B");
cache.get("a");                 // "a" is now the most recently used
cache.put("c", "C");            // evicts "b"
System.out.println(cache.keySet());   // [a, c]

Common mistake

Relying on a HashMap's iteration order. It depends on hash codes and capacity and can change when the map grows or between Java versions.

Under the hood

Iterating a HashMap walks every bucket, including empty ones, so a huge, mostly empty HashMap iterates slowly; a LinkedHashMap follows its list and only visits real entries. For caches in production, prefer a library such as Caffeine (size and time limits, statistics, concurrency), but the LinkedHashMap LRU is perfect for small, single-threaded caches and interviews.

Check yourself

With accessOrder = true, what does get(key) do to the entry?

How this connects

Where this leads

You've reached the end of this thread. Try a learning path for what's next.

Part of Java 8 and collections, practically.

Was this lesson helpful?

Finished reading? Mark it complete to track your progress.