AlgoInsight

Q&A

HashMap vs. Hashtable in Java

By AlgoInsight Team2026-06-18data-structuresoperating-systemsjava

Overview

Hashtable was introduced in Java 1.0; HashMap arrived in Java 2 (Collections Framework) with a cleaner API. They solve the same problem but embody different trade-offs around null handling and thread-safety. In modern code you almost always choose HashMap, and for concurrent access you reach for ConcurrentHashMap - Hashtable's synchronization design is considered obsolete.

graph TD
    A[Key-value map in Java] --> B[HashMap: fast, single-threaded]
    A --> C[Hashtable: synchronized, legacy]
    A --> D[ConcurrentHashMap: concurrent, modern]
    B --> B1[null key: 1 allowed<br/>null values: allowed]
    C --> C1[null key/value: NOT allowed]
    D --> D1[null key/value: NOT allowed]
    style B fill:#1e1b4b,color:#fff
    style D fill:#6366f1,color:#fff

Feature Comparison

Feature HashMap Hashtable
Thread-safe No Yes (synchronized methods)
Null keys One allowed Not allowed (NPE)
Null values Allowed Not allowed (NPE)
Performance Fast (no lock overhead) Slower (global lock)
Iteration order No guarantee No guarantee
Inheritance AbstractMap Dictionary (legacy)
Introduced Java 2 Java 1.0
Modern choice? Yes No (legacy)

HashMap Example

Map<String, Integer> map = new HashMap<>();
map.put("apple", 1);
map.put(null, 99);          // null key allowed
map.put("banana", null);    // null value allowed
map.get(null);              // 99

System.out.println(map.size());  // 3
map.forEach((k, v) -> System.out.println(k + "=" + v));

Hashtable Example

Map<String, Integer> legacy = new Hashtable<>();
legacy.put("apple", 1);
legacy.put(null, 1);    // ❌ NullPointerException
legacy.put("key", null);// ❌ NullPointerException

Why Hashtable's Synchronization Is Obsolete

Hashtable uses a single lock on the entire map - every get, put, remove acquires it. Under concurrent load this becomes a bottleneck since only one thread can touch the map at a time. ConcurrentHashMap (Java 5+) uses segment locking (Java 7) and later lock-free reads + CAS writes (Java 8+) - dramatically better concurrency.

// Modern concurrent map:
Map<String, Integer> concurrent = new ConcurrentHashMap<>();
concurrent.put("key", 1);
// null keys/values not allowed, but concurrent access is efficient

HashMap Is Not Thread-Safe - Consequences

If multiple threads modify a HashMap concurrently without external synchronization:

Map<String, Integer> safe = Collections.synchronizedMap(new HashMap<>());
// or, better:
Map<String, Integer> safe = new ConcurrentHashMap<>();

Iteration

HashMap.keySet(), values(), entrySet() return fail-fast iterators that throw ConcurrentModificationException if the map is modified during iteration (except through the iterator's remove). Hashtable's Enumeration does not fail-fast but is also outdated; modern code uses the iterator/stream APIs.

When to Use Each

Why This Matters in Interviews

Java collection interviews ask this constantly. The three key points: null handling (HashMap allows null key/value; Hashtable throws NPE), synchronization (Hashtable is synchronized/slow; HashMap is not, but that's usually fine since concurrent code should use ConcurrentHashMap), and modernity (Hashtable is legacy). Explaining why ConcurrentHashMap beats Hashtable (segment/CAS vs whole-map lock) and knowing Collections.synchronizedMap as an alternative shows depth.

Common Pitfalls

References

More answers