1. Обзор
В этом коротком руководстве мы сосредоточимся на основных различиях между Hashtable
и HashMap
.
2. Hashtable
и HashMap
в Java
Hashtable
и HashMap
очень похожи — обе коллекции реализуют интерфейс Map .
Кроме того, методы put()
, get()
, remove()
и containsKey()
обеспечивают производительность O(1) с постоянным временем. Внутри эти методы работают на основе общей концепции хеширования с использованием сегментов для хранения данных.
Ни один из классов не поддерживает порядок вставки элементов. Другими словами, первый добавленный элемент может не быть первым элементом, когда мы перебираем значения.
Но у них также есть некоторые различия, которые делают один лучше другого в некоторых ситуациях. Давайте рассмотрим эти различия поближе.
3. Различия между Hashtable
и HashMap
3.1. Синхронизация
Во- первых, Hashtable
является потокобезопасным и может совместно использоваться несколькими потоками в приложении.
С другой стороны, HashMap
не синхронизируется и не может быть доступен нескольким потокам без дополнительного кода синхронизации. Мы можем использовать Collections.synchronizedMap()
для создания потокобезопасной версии HashMap
. Мы также можем просто создать собственный код блокировки или сделать код потокобезопасным, используя ключевое слово synchronized
.
HashMap
не синхронизируется, поэтому он быстрее и использует меньше памяти, чем Hashtable
. Как правило, несинхронизированные объекты работают быстрее, чем синхронизированные, в однопоточном приложении.
3.2. Нулевые значения
Другим отличием является нулевая
обработка. HashMap
позволяет добавить одну запись
с нулем
в качестве ключа, а также множество записей с нулем
в качестве значения. Напротив, Hashtable
вообще не допускает null
. Давайте посмотрим на пример null
и HashMap
:
HashMap<String, String> map = new HashMap<String, String>();
map.put(null, "value");
map.put("key1", null);
map.put("key2", null);
Это приведет к:
assertEquals(3, map.size());
Далее давайте посмотрим, чем отличается Hashtable:
Hashtable<String, String> table = new Hashtable<String, String>();
table.put("key", null);
Это приводит к исключению NullPointerException
. Добавление объекта с нулевым
ключом также приводит к исключению NullPointerException
:
table.put(null, "value");
3.3. Итерация по элементам
HashMap
использует Iterator
для перебора значений, тогда как Hashtable
имеет Enumerator
для того же. Iterator является
преемником Enumerator
, который устраняет его несколько недостатков. Например, у Iterator
есть метод remove() для удаления элементов из базовых коллекций.
Iterator — отказоустойчивый итератор
. Другими словами, он генерирует исключение ConcurrentModificationException
, когда базовая коллекция изменяется во время итерации. Давайте посмотрим на пример отказоустойчивости: ``
HashMap<String, String> map = new HashMap<String, String>();
map.put("key1", "value1");
map.put("key2", "value2");
Iterator<String> iterator = map.keySet().iterator();
while(iterator.hasNext()){
iterator.next();
map.put("key4", "value4");
}
Это вызывает исключение ConcurrentModificationException
, потому что мы вызываем put()
во время итерации по коллекции.
4. Когда выбирать HashMap
вместо
Hashtable ``
Мы должны использовать HashMap
для несинхронизированного или однопоточного приложения.
Стоит отметить, что начиная с JDK 1.8 Hashtable
устарела. Однако ConcurrentHashMap
— отличная замена Hashtable .
Мы должны рассмотреть ConcurrentHashMap
для использования в приложениях с несколькими потоками.
5. Вывод
В этой статье мы проиллюстрировали различия между HashMap
и Hashtable
и то, что нужно иметь в виду, когда нам нужно выбрать один из них.
Как обычно, реализация всех этих примеров и фрагментов кода закончена на Github .