Definition
WeakHashMap behavior:
- Keys are weak references. The map does not prevent its keys from being GC'd.
- Auto-cleanup. When a key is collected, the entry (key + value) is removed from the map.
- Use case: Caching metadata about objects. When the object is GC'd, the cache entry is cleaned up automatically.
A bank keeps a note (entry) for each visiting customer (key). When the customer leaves the building (no strong reference), the note is automatically discarded at the next cleanup.
Understanding the Concepts
How it works
Map<Object, String> map = new WeakHashMap<>();
Object key1 = new Object(); // strong reference
map.put(key1, "data for key1");
Object key2 = new Object();
map.put(key2, "data for key2");
// Remove the strong reference to key2
key2 = null;
// After GC, key2's entry is eligible for removal
System.gc();
Thread.sleep(100);
System.out.println(map.size()); // likely 1 (key2's entry removed)
System.out.println(map.get(key1)); // "data for key1" (key1 still has strong ref)
When to use
- Metadata caches: Store extra info about objects. When the object is GC'd, the metadata is cleaned.
- Listener registries: Weak reference to the listener prevents memory leaks.
- ClassLoader caches: When the ClassLoader is GC'd, all cached classes are cleaned.
When NOT to use
- String literal keys: Literals are strongly referenced by the String Pool and are never GC'd.
- Integer keys in cache range: Cached Integer objects (-128 to 127) are never GC'd.
- Primary data storage: Entries can disappear unpredictably.
What should a senior engineer know?
- Entries are cleaned lazily – not immediately after GC, but during the next map operation (get, put, size).
- Values are strong references. If a value holds a strong reference back to its key, the key is not GC'd (retain cycle). Use
value = new WeakReference<>(actualValue)if needed. - ConcurrentHashMap with weak keys is not built-in. Use Caffeine or Guava's MapMaker for concurrent weak-key maps.
What are common mistakes?
A common mistake is not understanding the concept fully before using it in production banking applications.
Wrong approach:
package com.bank.service;
public class TransferService {
public void transfer(String fromAccount, String toAccount, double amount) {
// WRONG: using double for money
double balance = getBalance(fromAccount);
balance = balance - amount;
}
private double getBalance(String id) { return 10000.0; }
}
Correct approach:
package com.bank.service;
import java.math.BigDecimal;
public class TransferService {
public void transfer(String fromAccount, String toAccount, BigDecimal amount) {
// CORRECT: using BigDecimal for money
BigDecimal balance = getBalance(fromAccount);
balance = balance.subtract(amount);
}
private BigDecimal getBalance(String id) { return new BigDecimal("10000.00"); }
}
Always use BigDecimal for monetary calculations in banking systems to avoid floating-point precision errors.
What are the edge cases?
Edge cases can cause unexpected behavior in banking applications. Here are some to watch for.
package com.bank.edge;
public class EdgeCaseDemo {
public static void main(String[] args) {
// Edge case 1: null handling
String accountId = null;
try {
System.out.println(accountId.length());
} catch (NullPointerException e) {
System.out.println("Null account ID");
}
// Edge case 2: empty vs null
String emptyId = "";
System.out.println(emptyId.isEmpty()); // true
System.out.println(emptyId == null); // false
// Edge case 3: boundary values
java.math.BigDecimal zero = java.math.BigDecimal.ZERO;
java.math.BigDecimal negativeBalance = new java.math.BigDecimal("-0.01");
System.out.println(zero.compareTo(negativeBalance) > 0); // true
}
}
Null account ID
true
false
true
Always test with null values, empty strings, boundary values, and negative amounts in banking applications.
What are common interview follow-up questions?
Interviewers often follow up with these related questions:
- How does this concept apply to a high-throughput banking transaction system?
- What are the performance implications in a production environment?
- How would you debug issues related to this concept?
- What tools would you use to monitor this in production?
- How does this behave differently in Java 8 vs Java 17+?
When answering follow-up questions, always relate your answer back to practical experience. For example, at National Bank of India, Rajesh debugged a production issue related to this concept by using JFR recordings and heap dumps. Providing concrete examples from banking systems shows the interviewer that you understand both the theory and the practice.
Visual Overview
WeakHashMap:
key (weak ref) → value (strong ref)
key1 = new Object() → map.put(key1, "data")
key1 = null → key1 eligible for GC
After GC → entry (key1, "data") removed from map
Use: metadata caches, listener registries
Avoid: String/Integer keys (strongly referenced by pool/cache)
Key Takeaway
WeakHashMap uses weak reference keys. When no strong reference to a key exists, the entry is automatically removed after GC. Use it for metadata caches and listener registries where entries should disappear when the key object is no longer in use.
One sentence to remember: WeakHashMap auto-removes entries when the key is garbage collected – use for caches, not for primary data.
---