Короткий ответ
Главное отличие — потокобезопасность: у Hashtable синхронизированы все методы, и из-за глобальной синхронизации на каждый вызов она медленнее; HashMap не синхронизирован и безопасен только для одного потока. Второе важное отличие — работа с null: HashMap допускает один null-ключ и любое количество null-значений, а Hashtable выбрасывает NullPointerException на ключ или значение null.
Как это работает подробнее
В HashMap для null предусмотрен специальный путь: такой ключ попадает в корзину с индексом 0 без вызова hashCode, поэтому null разрешён; дизайн Hashtable такой поддержки не предполагает. Наследования между классами нет: HashMap унаследован от AbstractMap, а Hashtable — от Dictionary, это разные ветви иерархии. Итераторы и HashMap, и Hashtable являются fail-fast.
- Современная замена:
ConcurrentHashMapдаёт более высокую конкурентность за счёт сегментации, а в Java 8+ — CAS-операций с точечной синхронизацией отдельных корзин. - Общее: и Hashtable, и ConcurrentHashMap не допускают
null-ключи иnull-значения.
Пример кода
NullKeyDemo.java
Map<String, String> map = new HashMap<>();
map.put(null, "value"); // допустимо: null-ключ в корзине 0
map.put("key", null); // допустимо: null-значение
Hashtable<String, String> table = new Hashtable<>();
table.put(null, "value"); // NullPointerExceptionЧто использовать на практике
- В однопоточном коде берите HashMap.
- В многопоточном коде берите ConcurrentHashMap, а не Hashtable.
- Hashtable оставляйте только в legacy-коде; новые решения на ней не стройте.
Подводные камни
- Попытка положить
nullв Hashtable или ConcurrentHashMap приводит кNullPointerException. - HashMap «потокобезопасен» только при отсутствии конкуренции: параллельные изменения могут испортить внутреннюю структуру.
- Не называйте Hashtable корректной «потокобезопасной альтернативой HashMap» — современный ответ — ConcurrentHashMap.
Как отвечать на собеседовании
- Перечислите три главных отличия: синхронизация и скорость, отношение к null, место в иерархии (AbstractMap против Dictionary) → добавьте, что итераторы обоих классов fail-fast → завершите рекомендацией: HashMap для одного потока, ConcurrentHashMap для многих, Hashtable — устаревший класс.