00:00

Difference Between HashMap and WeakHashMap in Java

HashMap and WeakHashMap look the same from the outside: both implement Map, use hashing, and allow null keys and values. The crucial difference is how they hold their keys:

  • HashMap holds strong references. A key stays in memory as long as it is in the map, even if nothing else uses it.
  • WeakHashMap holds keys through weak references. When no other strong reference to a key remains, the garbage collector may reclaim it, and its entry disappears from the map automatically.

1. Comparison Table

AspectHashMapWeakHashMap
Key referencesStrongWeak (WeakReference)
Entry lifetimeUntil removed explicitlyRemoved automatically after the key is garbage-collected
SizeStableCan shrink at any time, without your code removing anything
ValuesStrongStrong (a value referring back to its key prevents collection)
NullsOne null key, null valuesOne null key, null values
Cloneable / SerializableYesNo
Typical useGeneral key–value storageMetadata attached to objects, canonicalising caches
Thread-safeNoNo

2. Garbage Collection in Action

WeakVsStrong.java
import java.util.*;

public class WeakVsStrong {
    static class Session {
        final String user;
        Session(String user) { this.user = user; }
        public String toString() { return "Session(" + user + ")"; }
    }

    static void waitForGc(Map<?, ?> map, int expected) throws InterruptedException {
        for (int i = 0; i < 50 && map.size() > expected; i++) { System.gc(); Thread.sleep(20); }
    }

    public static void main(String[] args) throws InterruptedException {
        Map<Session, String> strong = new HashMap<>();
        Map<Session, String> weak = new WeakHashMap<>();

        Session s1 = new Session("asha"), s2 = new Session("ravi");
        strong.put(s1, "cart-1"); strong.put(s2, "cart-2");
        weak.put(new Session("asha"), "cart-1");
        Session kept = new Session("ravi");
        weak.put(kept, "cart-2");

        s1 = null; s2 = null;          // drop our references to the HashMap keys
        waitForGc(weak, 1);            // the weak key "asha" has no strong reference

        System.out.println("HashMap size     : " + strong.size() + "  (keys kept alive by the map)");
        System.out.println("WeakHashMap size : " + weak.size() + "  (unreferenced key removed by GC)");
        System.out.println("remaining weak   : " + weak.keySet());
        System.out.println("kept still used  : " + kept.user);
    }
}
Output
HashMap size     : 2  (keys kept alive by the map)
WeakHashMap size : 1  (unreferenced key removed by GC)
remaining weak   : [Session(ravi)]
kept still used  : ravi

After the program drops its references, the HashMap still keeps both sessions alive, a classic source of memory leaks in caches. The WeakHashMap loses the entry whose key is no longer referenced elsewhere. Garbage collection timing is not guaranteed, so the example calls System.gc() repeatedly for the demonstration.

3. Use Case and Pitfalls

MetadataCache.java
import java.util.*;

public class MetadataCache {
    // Attach extra data to objects you don't own, without keeping them alive
    static final Map<Object, String> labels = new WeakHashMap<>();

    public static void main(String[] args) throws InterruptedException {
        Object widget = new Object();
        labels.put(widget, "primary button");
        System.out.println("label: " + labels.get(widget));

        widget = null;                                     // widget no longer used anywhere
        for (int i = 0; i < 50 && !labels.isEmpty(); i++) { System.gc(); Thread.sleep(20); }
        System.out.println("entries after widget is gone: " + labels.size());

        // Pitfall: String literals are interned and never collected, so they make poor weak keys
        Map<String, Integer> literals = new WeakHashMap<>();
        literals.put("constant", 1);
        System.gc();
        System.out.println("literal key still present: " + literals.containsKey("constant"));
    }
}
Output
label: primary button
entries after widget is gone: 0
literal key still present: true
  • Good use: associating extra data with objects whose lifetime you do not control (UI components, class loaders, request objects), so the data disappears with the object.
  • String literals and boxed small integers are cached by the JVM and never collected, so they make useless weak keys.
  • Values must not reference their keys, or the keys stay strongly reachable.
  • Iteration results and size() can change between calls; treat the map as a cache, not as reliable storage.
  • For real caches with size limits and expiry, prefer a library such as Caffeine; for value-based caches, SoftReference is sometimes more appropriate.

4. Summary

  • HashMap keeps keys alive; WeakHashMap lets the GC remove entries whose keys are no longer used.
  • Both allow nulls, use hashing and are not thread-safe.
  • Use WeakHashMap for metadata tied to object lifetimes, not for normal data.
  • Avoid interned or cached objects as weak keys.

Related Tutorials