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
| Aspect | HashMap | Hashtable |
|---|---|---|
| Synchronization | Not synchronized | Every public method synchronized |
| Null keys / values | One null key, any null values | Neither (throws NullPointerException) |
| Performance | Faster | Slower due to locking |
| Introduced | Java 1.2 | Java 1.0 (legacy) |
| Superclass | AbstractMap | Dictionary (obsolete) |
| Iteration | Iterator (fail-fast) | Iterator and legacy Enumeration (not fail-fast) |
| Default capacity / growth | 16, doubles | 11, grows to 2n + 1 |
| Collision handling | Buckets turn into trees when large (Java 8+) | Linked lists only |
| Extra legacy methods | – | elements(), keys(), contains(value) |
| Recommended? | Yes | No; use ConcurrentHashMap |
2. Nulls and Legacy API
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));
}
}
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:
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)");
}
}
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?
HashMapfor maps used by one thread (the common case).ConcurrentHashMapfor maps shared between threads.LinkedHashMaporTreeMapwhen you need insertion or sorted order.Hashtableonly for legacy APIs that require it.
5. Summary
HashMap: unsynchronized, fast, allows nulls.Hashtable: synchronized, slower, no nulls, legacyDictionaryAPI.- Both provide O(1) average operations and no ordering.
- Replace
HashtablewithConcurrentHashMapfor thread-safe maps.
Related Tutorials
Frequently Asked Questions (FAQ)
Q1. What is the main difference between HashMap and Hashtable?
Hashtable is synchronized and does not allow nulls; HashMap is unsynchronized and allows one null key and null values.
Q2. Why does Hashtable not allow null keys or values?
It calls hashCode() on keys and uses null returns from get to mean "absent", so nulls were disallowed by design.
Q3. Which is faster?
HashMap, because it does not lock on every operation.
Q4. Is Hashtable deprecated?
No, but it is a legacy class. Use HashMap or ConcurrentHashMap instead.
Q5. How do I make a HashMap thread-safe?
Use ConcurrentHashMap, or wrap it with Collections.synchronizedMap.
Q6. What is the difference between Hashtable and ConcurrentHashMap?
Both are thread-safe and reject nulls, but ConcurrentHashMap uses fine-grained locking and lock-free reads, giving far better concurrency, and its iterators are weakly consistent instead of fail-fast.
Q7. What is the default capacity of each?
HashMap: 16; Hashtable: 11. Both use a load factor of 0.75.
Q8. Do they maintain order?
No. Use LinkedHashMap for insertion order or TreeMap for sorted keys.
Q9. Is Enumeration fail-fast?
No. Hashtable's Enumeration is not fail-fast, while iterators of both classes are.
Q10. Which class does Hashtable extend?
The obsolete abstract class Dictionary; it also implements Map.
Q11. Does Hashtable use tree bins like HashMap?
No. Only HashMap (and ConcurrentHashMap) convert crowded buckets into balanced trees.
Q12. Is Collections.synchronizedMap the same as Hashtable?
Similar: every method synchronizes on one lock. It allows nulls if the underlying map does. You must still lock it while iterating.
Q13. Can I iterate a Hashtable safely while another thread modifies it?
No. Iterators throw ConcurrentModificationException; synchronize on the table while iterating or use ConcurrentHashMap.
Q14. Which is used by Properties?
java.util.Properties extends Hashtable<Object, Object>, one of its remaining common uses.
Q15. Do both rely on hashCode and equals?
Yes. Keys must implement them consistently.
Q16. What does Hashtable.contains() do?
It checks for a value, same as containsValue, not for a key.
Q17. Is a compound check-then-put atomic in Hashtable?
No. Two separate calls can interleave. Use putIfAbsent or ConcurrentHashMap.compute.
Q18. Can I convert one to the other?
Yes: new HashMap<>(hashtable), or new Hashtable<>(hashMap) if the map contains no nulls.
Q19. Do both have the same time complexity?
Yes, O(1) average for get and put; HashMap's tree bins improve the worst case to O(log n).
Q20. Is this asked in interviews?
Frequently. Cover synchronization, nulls, performance, legacy status and ConcurrentHashMap.