LinkedHashMap and Specialized Maps
Master LinkedHashMap for predictable iteration and LRU caching. Explore WeakHashMap for memory-sensitive caching and IdentityHashMap for reference-based equality. Build production-ready caches in under 20 lines of code.
📋 At a Glance
| Aspect | Details |
|---|---|
| Topic | LinkedHashMap, WeakHashMap, IdentityHashMap, EnumMap |
| Complexity | Intermediate to Advanced |
| Prerequisites | Part 12 (HashMap Internals) |
| Time to Master | 3-4 hours |
| Interview Frequency | Very High (LRU cache implementation) |
🎯 What You'll Learn
After completing this article, you will be able to:
- Implement LRU cache with LinkedHashMap in 20 lines
- Understand accessOrder vs insertionOrder in LinkedHashMap
- Use WeakHashMap for memory-sensitive caching
- Apply IdentityHashMap for reference equality scenarios
- Choose the right specialized map for each use case
Production Story: The 20-Line LRU Cache That Saved the Day
The Incident
Our image processing service was running out of memory. Each processed image was being cached indefinitely, and with thousands of requests per minute, we were hitting OOM errors.
JAVA(12 lines)CodeLoading syntax highlighter...
The ops team was scaling up servers, but the real problem was unbounded cache growth.
The 20-Line Fix
JAVA(18 lines)CodeLoading syntax highlighter...
How It Works
TEXT(15 lines)CodeLoading syntax highlighter...
The removeEldestEntry Hook
JAVA(15 lines)CodeLoading syntax highlighter...
Impact
- Memory usage dropped from 8GB to 500MB
- Response time improved (less GC pressure)
- Zero additional dependencies
- Solution fits in a single file
Mental Model: The Restaurant Waiting List
TEXT(30 lines)CodeLoading syntax highlighter...
Deep Dive: LinkedHashMap Internals
Entry Structure
JAVA(10 lines)CodeLoading syntax highlighter...
Visual: HashMap + Linked List
TEXT(20 lines)CodeLoading syntax highlighter...
Construction Options
JAVA(19 lines)CodeLoading syntax highlighter...
Access Order Behavior
JAVA(21 lines)CodeLoading syntax highlighter...
Deep Dive: LRU Cache Implementation
Basic LRU Cache
JAVA(18 lines)CodeLoading syntax highlighter...
LRU Cache with Expiration
JAVA(43 lines)CodeLoading syntax highlighter...
LRU Cache with Load Function
JAVA(27 lines)CodeLoading syntax highlighter...
Deep Dive: WeakHashMap
How WeakHashMap Works
JAVA(12 lines)CodeLoading syntax highlighter...
WeakHashMap Internals
JAVA(18 lines)CodeLoading syntax highlighter...
WeakHashMap Use Cases
JAVA(23 lines)CodeLoading syntax highlighter...
WeakHashMap Gotchas
JAVA(18 lines)CodeLoading syntax highlighter...
Deep Dive: IdentityHashMap
Reference Equality vs Object Equality
JAVA(21 lines)CodeLoading syntax highlighter...
IdentityHashMap Use Cases
JAVA(23 lines)CodeLoading syntax highlighter...
IdentityHashMap Internals
JAVA(9 lines)CodeLoading syntax highlighter...
Deep Dive: EnumMap
Ultra-Fast Enum Key Maps
JAVA(16 lines)CodeLoading syntax highlighter...
EnumMap Performance
JAVA(9 lines)CodeLoading syntax highlighter...
Specialized Map Comparison
TEXT(13 lines)CodeLoading syntax highlighter...
⚠️ Common Mistakes
Mistake 1: Forgetting accessOrder Parameter
JAVA(7 lines)CodeLoading syntax highlighter...
Mistake 2: WeakHashMap with Strong Value References
JAVA(14 lines)CodeLoading syntax highlighter...
Mistake 3: Using WeakHashMap for Value-Based Caching
JAVA(9 lines)CodeLoading syntax highlighter...
Mistake 4: Modifying LinkedHashMap During Iteration
JAVA(19 lines)CodeLoading syntax highlighter...
Mistake 5: IdentityHashMap with Immutable Keys
JAVA(11 lines)CodeLoading syntax highlighter...
🐛 Debug This
Challenge 1: The Non-Evicting Cache
JAVA(14 lines)CodeLoading syntax highlighter...
[C, A, D]- After puts: A, B, C (insertion order)
- get("A") moves A to end: B, C, A
- put("D") adds D, size=4 > 3, removes eldest (B): C, A, D
Challenge 2: The Immortal Entry
JAVA(8 lines)CodeLoading syntax highlighter...
1"key"is a string literal (interned), always reachable → staysnew String("key2")has no other references → collected by GC
Challenge 3: The Identity Puzzle
JAVA(7 lines)CodeLoading syntax highlighter...
2Integer caches values from -128 to 127. So:
100is cached → same object both times → 1 entry200is NOT cached → different objects → 2 entries
Wait, that would be 3 entries. Let me reconsider...
Actually:
- First
100and second100are same cached object → 1 entry - First
200and second200are different objects (no caching) → 2 entries
Total: 3 entries? Let me verify the Integer cache behavior...
100 literals are the same object. 200 is outside the range, so 200 creates new Integer objects each time.3 (one for 100, two for different 200 objects)💻 Exercises
Exercise 1: Thread-Safe LRU Cache
Implement a thread-safe LRU cache:
JAVA(5 lines)CodeLoading syntax highlighter...
JAVA(33 lines)CodeLoading syntax highlighter...
Exercise 2: WeakValueHashMap
Implement a map where values (not keys) are weakly referenced:
JAVA(5 lines)CodeLoading syntax highlighter...
JAVA(38 lines)CodeLoading syntax highlighter...
Exercise 3: Most Recently Used (MRU) Cache
Implement a cache that evicts the MOST recently used item (opposite of LRU):
JAVA(4 lines)CodeLoading syntax highlighter...
JAVA(32 lines)CodeLoading syntax highlighter...
Exercise 4: Caching with Soft References
Implement a memory-sensitive cache using SoftReferences:
JAVA(5 lines)CodeLoading syntax highlighter...
JAVA(38 lines)CodeLoading syntax highlighter...
Exercise 5: Object Graph Size Calculator
Use IdentityHashMap to calculate unique object count in an object graph:
JAVA(4 lines)CodeLoading syntax highlighter...
JAVA(42 lines)CodeLoading syntax highlighter...
🎤 Senior-Level Interview Questions
Question 1: LRU Cache Implementation
JAVA(18 lines)CodeLoading syntax highlighter...
Question 2: LinkedHashMap Access Order
Operations that trigger reordering (move to end):
get(key)when key existsput(key, value)- both insert and updateputIfAbsent(key, value)when key doesn't existcompute(),computeIfAbsent(),computeIfPresent()merge()replace()
Operations that DON'T trigger reordering:
containsKey(key)- read-only checkcontainsValue(value)- read-only check- Iteration - doesn't modify structure
remove(key)- removes, doesn't reorder
Question 3: WeakHashMap GC Behavior
Entries are removed lazily, not immediately after key is GC'd:
- Key becomes unreachable
- GC runs and collects the key
- WeakReference is added to ReferenceQueue
- Next WeakHashMap operation polls queue and removes stale entries
JAVA(9 lines)CodeLoading syntax highlighter...
get(), put(), size(), containsKey(), iteration, etc.Question 4: IdentityHashMap Use Cases
Use IdentityHashMap when:
- Object graph traversal: Track visited objects without equals() interference
- Serialization: Map objects to IDs by identity
- Proxy/wrapper tracking: Original object → proxy mapping
- Interned object handling: When you specifically want reference equality
JAVA(12 lines)CodeLoading syntax highlighter...
Question 5: EnumMap Performance
EnumMap uses the enum's ordinal as array index:
JAVA(14 lines)CodeLoading syntax highlighter...
Question 6: Thread Safety in LinkedHashMap
Three approaches:
JAVA(24 lines)CodeLoading syntax highlighter...
📝 Summary & Key Takeaways
LinkedHashMap
- HashMap + doubly-linked list for ordering
- insertionOrder (default) or accessOrder (for LRU)
removeEldestEntry()hook for cache eviction- O(1) operations, slight memory overhead for links
LRU Cache Pattern
JAVA(5 lines)CodeLoading syntax highlighter...
WeakHashMap
- Keys are WeakReferences, auto-collected by GC
- Use for caches where key lifecycle controls entry lifecycle
- Cleanup is lazy (on next operation)
- Don't use with string literals or when value references key
IdentityHashMap
- Uses
==instead ofequals() - Use for object graph traversal, serialization
- More memory-efficient for small maps
- Linear probing instead of chaining
EnumMap
- O(1) array-indexed by ordinal
- Always use for enum keys (no exceptions!)
- Most memory-efficient map for enums
🏁 Conclusion
Specialized maps solve specific problems elegantly. LinkedHashMap enables LRU caches in 20 lines, WeakHashMap provides automatic cleanup tied to GC, and IdentityHashMap handles reference equality scenarios. Knowing when to use each saves hours of custom implementation.
Key takeaways:
- LRU cache = LinkedHashMap with accessOrder=true + removeEldestEntry
- WeakHashMap for key-lifecycle-based caching - not for value-based expiration
- IdentityHashMap for object identity - graph traversal, serialization
- EnumMap for enum keys - always, no exceptions
- Thread safety requires extra work - use Caffeine for production caches
In the next article, we'll explore PriorityQueue and heap-based data structures - essential for scheduling, task prioritization, and the classic "top K" problems.
📅 Review Schedule
To solidify your understanding, review this material:
- Tomorrow: Implement an LRU cache from memory
- In 3 days: Explain WeakHashMap GC behavior to a colleague
- In 1 week: Review IdentityHashMap use cases
- In 2 weeks: Compare all specialized maps from memory