HashMap vs Hashtable
Hashtable is from Java 1.0; HashMap arrived with the Collections framework in Java 1.2. Today Hashtable is legacy:
- Every method is synchronized on the whole table. One thread at a time, even for reads, so it's slow when several threads use it.
- No null keys or values (
NullPointerException). - It still offers old-style
Enumerations and extends the obsoleteDictionaryclass. - It never gained HashMap's modern internals, such as tree buckets.
HashMap isn't synchronized, allows one null key and null values, and is the right choice in single-threaded code. When several threads share a map, use ConcurrentHashMap, never Hashtable: it's thread-safe and much faster under concurrency.
Side by side
| HashMap | Hashtable | |
|---|---|---|
| Introduced | Java 1.2 (Collections framework) | Java 1.0 (legacy) |
| Thread-safe | No | Yes: every method synchronized |
| Performance | Fast | Slow under contention (one lock for everything) |
| null keys / values | One null key, any number of null values | Neither: NullPointerException |
| Iteration | Fail-fast Iterator | Enumeration (not fail-fast) or fail-fast Iterator |
| Superclass | AbstractMap | Dictionary (obsolete) |
| Crowded buckets | List, then tree (Java 8+) | List only |
| Default capacity | 16 (power of two) | 11 |
| Use today | Single-threaded code | Don't: use ConcurrentHashMap |
Example
Map<String, Integer> hm = new HashMap<>();
hm.put(null, 1); // fine
hm.put("a", null); // fine
Map<String, Integer> ht = new Hashtable<>();
// ht.put(null, 1); // NullPointerException
// ht.put("a", null); // NullPointerException
// Even a synchronized map doesn't make "check then act" safe:
if (!ht.containsKey("visits")) { // another thread can put() right here...
ht.put("visits", 1); // ...and this overwrites it
}
ht.putIfAbsent("visits", 1); // one atomic call: correctCommon mistake
Choosing Hashtable "for thread safety". It's slower than ConcurrentHashMap and still doesn't make multi-step operations safe.
Under the hood
Synchronizing each method makes each call atomic, not a sequence of calls. That's why check-then-act code (containsKey then put, get then put) is still broken on Hashtable and Collections.synchronizedMap; use atomic methods such as putIfAbsent, compute and merge on a ConcurrentHashMap instead.
Check yourself
Which of these accepts a null key?
How this connects
Know these first
Where this leads
You've reached the end of this thread. Try a learning path for what's next.
Part of Java 8 and collections, practically.
Was this lesson helpful?
Finished reading? Mark it complete to track your progress.