00:00

Difference Between HashMap and Hashtable in Java

HashMap and Hashtable both store key–value pairs in a hash table with O(1) average lookups. The important differences are that Hashtable is synchronized and rejects nulls, while HashMap is unsynchronized and allows one null key and null values. Hashtable is a legacy class from Java 1.0; for new code use HashMap, or ConcurrentHashMap when the map is shared between threads.

1. Comparison Table

AspectHashMapHashtable
SynchronizationNot synchronizedEvery public method synchronized
Null keys / valuesOne null key, any null valuesNeither (throws NullPointerException)
PerformanceFasterSlower due to locking
IntroducedJava 1.2Java 1.0 (legacy)
SuperclassAbstractMapDictionary (obsolete)
IterationIterator (fail-fast)Iterator and legacy Enumeration (not fail-fast)
Default capacity / growth16, doubles11, grows to 2n + 1
Collision handlingBuckets turn into trees when large (Java 8+)Linked lists only
Extra legacy methods–elements(), keys(), contains(value)
Recommended?YesNo; use ConcurrentHashMap

2. Nulls and Legacy API

NullsAndApi.java
import java.util.*;

public class NullsAndApi {
    public static void main(String[] args) {
        Map<String, String> hashMap = new HashMap<>();
        hashMap.put(null, "no key");          // one null key allowed
        hashMap.put("city", null);            // null values allowed
        System.out.println("HashMap   : " + hashMap.containsKey(null) + ", city=" + hashMap.get("city"));

        Hashtable<String, String> table = new Hashtable<>();
        try { table.put(null, "x"); }
        catch (NullPointerException e) { System.out.println("Hashtable : null key -> NullPointerException"); }
        try { table.put("city", null); }
        catch (NullPointerException e) { System.out.println("Hashtable : null value -> NullPointerException"); }

        // Legacy API: Enumeration and contains(value)
        table.put("a", "1"); table.put("b", "2");
        Enumeration<String> keys = table.keys();
        List<String> seen = new ArrayList<>();
        while (keys.hasMoreElements()) seen.add(keys.nextElement());
        Collections.sort(seen);
        System.out.println("Enumeration keys: " + seen + ", contains(\"2\"): " + table.contains("2"));
        System.out.println("Hashtable extends Dictionary: " + (table instanceof Dictionary));
    }
}
Output
HashMap   : true, city=null
Hashtable : null key -> NullPointerException
Hashtable : null value -> NullPointerException
Enumeration keys: [a, b], contains("2"): true
Hashtable extends Dictionary: true

3. Thread Safety

Two threads increment a shared counter 10,000 times each:

ConcurrentChoice.java
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

public class ConcurrentChoice {
    static int count(Map<String, Integer> map) throws InterruptedException {
        Runnable task = () -> { for (int i = 0; i < 10_000; i++) map.merge("hits", 1, Integer::sum); };
        Thread a = new Thread(task), b = new Thread(task);
        a.start(); b.start(); a.join(); b.join();
        return map.get("hits");
    }

    public static void main(String[] args) throws InterruptedException {
        System.out.println("Hashtable         : " + count(new Hashtable<>()));
        System.out.println("ConcurrentHashMap : " + count(new ConcurrentHashMap<>()));
        System.out.println("HashMap (unsafe)  : " + count(new HashMap<>()) + "  (usually less than 20000)");
    }
}
Output (sample run; the HashMap result varies)
Hashtable         : 20000
ConcurrentHashMap : 20000
HashMap (unsafe)  : 11962  (usually less than 20000)

Hashtable is correct here but locks the whole table for every call, so threads queue up. ConcurrentHashMap is also correct and scales much better: reads are lock-free, and writes lock only small parts of the table. It also offers atomic compound operations like merge, compute and putIfAbsent. Like Hashtable, it rejects null keys and values.

4. Which Should You Use?

  • HashMap for maps used by one thread (the common case).
  • ConcurrentHashMap for maps shared between threads.
  • LinkedHashMap or TreeMap when you need insertion or sorted order.
  • Hashtable only for legacy APIs that require it.

5. Summary

  • HashMap: unsynchronized, fast, allows nulls.
  • Hashtable: synchronized, slower, no nulls, legacy Dictionary API.
  • Both provide O(1) average operations and no ordering.
  • Replace Hashtable with ConcurrentHashMap for thread-safe maps.

Related Tutorials