Различия между HashMap и Hashtable? - PullRequest
       316

Различия между HashMap и Hashtable?

3465 голосов
/ 03 сентября 2008

Каковы различия между HashMap и Hashtable в Java?

Что более эффективно для непоточных приложений?

Ответы [ 34 ]

34 голосов
/ 08 сентября 2011

Другое ключевое отличие между hashtable и hashmap состоит в том, что Iterator в HashMap является отказоустойчивым, а перечислитель для Hashtable - нет, и генерирует ConcurrentModificationException, если какой-либо другой поток изменяет карту структурно, добавляя или удаляя любой элемент, кроме собственного удаления Iterator ( ) метод. Но это не гарантированное поведение, и JVM сделает все возможное. "

Мой источник: http://javarevisited.blogspot.com/2010/10/difference-between-hashmap-and.html

33 голосов
/ 12 января 2012

Помимо всех других важных аспектов, уже упомянутых здесь, API-интерфейс Collections (например, интерфейс карты) постоянно изменяется, чтобы соответствовать «последним и лучшим» дополнениям спецификации Java.

Например, сравните итерацию Java 5 Map:

for (Elem elem : map.keys()) {
  elem.doSth();
}

по сравнению со старым подходом Hashtable:

for (Enumeration en = htable.keys(); en.hasMoreElements(); ) {
  Elem elem = (Elem) en.nextElement();
  elem.doSth();
}

В Java 1.8 нам также обещают создавать и получать доступ к HashMaps, как в старых добрых скриптовых языках:

Map<String,Integer> map = { "orange" : 12, "apples" : 15 };
map["apples"];

Обновление: Нет, они не приземлятся в 1,8 ...: (

Будут ли улучшения в Project Coin в JDK8?

28 голосов
/ 29 апреля 2012
  • HashTable синхронизируется, если вы используете его в одном потоке, вы можете использовать HashMap , который является несинхронизированной версией. Несинхронизированные объекты часто немного более производительны. Кстати, если несколько потоков обращаются к HashMap одновременно, и хотя бы один из потоков структурно изменяет карту, она должна быть синхронизирована извне. Вы можете обернуть несинхронизированную карту в синхронизированную, используя:

    Map m = Collections.synchronizedMap(new HashMap(...));
    
  • HashTable может содержать ненулевой объект только в качестве ключа или значения. HashMap может содержать один нулевой ключ и нулевые значения.

  • Итераторы, возвращаемые Map, работают быстро, если карта структурно изменена в любое время после создания итератора, любым способом, кроме как через собственный метод удаления итератора, итератор выдаст ConcurrentModificationException , Таким образом, перед одновременной модификацией итератор быстро и чисто дает сбой, вместо того, чтобы рисковать произвольным недетерминированным поведением в неопределенное время в будущем. Принимая во внимание, что Перечисления, возвращаемые методами ключей и элементов Hashtable, не являются быстрыми при сбое.

  • HashTable и HashMap являются членами Java Collections Framework (начиная с платформы Java 2 v1.2, HashTable был модернизирован для реализации интерфейса Map).

  • HashTable считается устаревшим кодом, документация рекомендует использовать ConcurrentHashMap вместо Hashtable, если требуется многопоточная реализация с высокой степенью параллелизма.

  • HashMap не гарантирует порядок, в котором элементы возвращаются. Что касается HashTable, я думаю, что это то же самое, но я не совсем уверен, я не нахожу ресурсы, которые бы четко указывали это.

27 голосов
/ 10 декабря 2012

HashMap и Hashtable также имеют существенные алгоритмические различия. Никто не упоминал об этом раньше, поэтому я поднимаю это. HashMap создаст хэш-таблицу со степенью двойного размера, динамически увеличит ее так, чтобы в каждом баке было не более восьми элементов (столкновений), и будет очень хорошо перемешивать элементы для общих типов элементов. Однако реализация Hashtable обеспечивает лучший и более точный контроль над хэшированием, если вы знаете, что делаете, а именно, вы можете фиксировать размер таблицы, например, с помощью. самое близкое простое число к размеру вашего домена значений, и это приведет к лучшей производительности, чем HashMap, то есть меньше коллизий в некоторых случаях.

Помимо очевидных различий, широко обсуждаемых в этом вопросе, я рассматриваю Hashtable как автомобиль с «ручным приводом», где вы лучше контролируете хеширование, а HashMap как аналог «с автоматическим приводом», который в целом будет хорошо работать. 1007 *

25 голосов
/ 03 сентября 2008

Hashtable синхронизируется, а HashMap - нет. Это делает Hashtable медленнее, чем Hashmap.

Для непоточных приложений используйте HashMap, поскольку в остальном они одинаковы по функциональности.

23 голосов
/ 03 сентября 2008

На основании информации здесь , я бы порекомендовал перейти с HashMap. Я думаю, что самым большим преимуществом является то, что Java не позволит вам изменять его, пока вы выполняете итерацию, если вы не сделаете это через итератор.

21 голосов
/ 04 января 2018

A Collection - иногда называемый контейнером - это просто объект, который группирует несколько элементов в одну единицу. Collection s используются для хранения, извлечения, обработки и передачи агрегированных данных. Структура коллекций W - это унифицированная архитектура для представления и управления коллекциями.

HashMap JDK1.2 и Hashtable JDK1.0, оба используются для представления группы объектов, представленных в паре <Key, Value>. Каждая пара <Key, Value> называется Entry объектом. Коллекция записей ссылается на объект HashMap и Hashtable. Ключи в коллекции должны быть уникальными или отличительными. [поскольку они используются для получения сопоставленного значения определенного ключа. значения в коллекции могут быть продублированы.]


« Элемент инфраструктуры суперкласса, Legacy и Collection

Hashtable - это устаревший класс, представленный в JDK1.0, который является подклассом класса Dictionary. С JDK1.2 Hashtable перепроектирован для реализации интерфейса Map , чтобы сделать его частью структуры коллекции. HashMap является членом Java Collection Framework с самого начала его появления в JDK1.2. HashMap является подклассом класса AbstractMap.

public class Hashtable<K,V> extends Dictionary<K,V> implements Map<K,V>, Cloneable, Serializable { ... }

public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable { ... }

« Начальная емкость и коэффициент нагрузки

Емкость - это количество сегментов в хэш-таблице, а начальная емкость - это просто емкость на момент создания хеш-таблицы. Обратите внимание, что хэш-таблица открыта: в случае «hashcollision» в одном сегменте хранится несколько записей, которые необходимо искать последовательно. Коэффициент загрузки - это мера того, насколько полной хеш-таблице разрешено получать до автоматического увеличения ее емкости.

HashMap создает пустую хеш-таблицу с начальной емкостью по умолчанию (16) и коэффициентом загрузки по умолчанию (0,75). Где в качестве Hashtable создается пустая таблица с начальной емкостью по умолчанию (11) и коэффициентом загрузки / коэффициентом заполнения (0,75).

Hash Map & Hashtable

« Структурная модификация в случае столкновения хеша

HashMap, Hashtable в случае коллизий хешей они сохраняют записи карты в связанных списках. Из Java8 для HashMap, если объем хеш-памяти превышает определенный порог, этот сегмент переключится с linked list of entries to a balanced tree. которые улучшают производительность в худшем случае с O (n) до O (log n). При преобразовании списка в двоичное дерево хеш-код используется как переменная ветвления. Если в одном сегменте находятся два разных хэш-кода, один считается больше и идет справа от дерева, а другой - слева. Но когда оба хеш-кода равны, HashMap предполагает, что ключи сравнимы, и сравнивает ключ, чтобы определить направление, чтобы можно было поддерживать некоторый порядок. Хорошей практикой является сопоставление ключей HashMap . При добавлении записей, если размер сегмента достигает TREEIFY_THRESHOLD = 8, преобразовать связанный список записей в сбалансированное дерево, при удалении записей, меньших TREEIFY_THRESHOLD и не более UNTREEIFY_THRESHOLD = 6, преобразовать сбалансированное дерево в связанный список записей. Java 8 SRC , стека

« Итерация в режиме сбора данных, Fail-Fast и Fail-Safe

    +--------------------+-----------+-------------+
    |                    | Iterator  | Enumeration |
    +--------------------+-----------+-------------+
    | Hashtable          | fail-fast |    safe     |
    +--------------------+-----------+-------------+
    | HashMap            | fail-fast | fail-fast   |
    +--------------------+-----------+-------------+
    | ConcurrentHashMap  |   safe    |   safe      |
    +--------------------+-----------+-------------+

Iterator является безотказным по своей природе. то есть он генерирует исключение ConcurrentModificationException, если коллекция модифицируется при выполнении итерации, отличной от собственного метода remove (). Где, как Enumeration является отказоустойчивым по своей природе. Он не выдает никаких исключений, если коллекция изменяется во время итерации.

Согласно Java API Docs, Iterator всегда предпочтительнее, чем Enumeration.

ПРИМЕЧАНИЕ: Функциональность интерфейса Enumeration дублируется интерфейсом Iterator. Кроме того, Iterator добавляет необязательную операцию удаления и имеет более короткие имена методов. Новые реализации должны рассмотреть возможность использования Iterator вместо Enumeration.

В Java 5 представила интерфейс ConcurrentMap : ConcurrentHashMap - высококонкурентная, высокопроизводительная реализация ConcurrentMap, поддерживаемая хеш-таблицей. Эта реализация никогда не блокируется при выполнении поиска и позволяет клиенту выбирать уровень параллелизма для обновлений. Он предназначен для замены Hashtable: в дополнение к реализации ConcurrentMap он поддерживает все "устаревшие" методы, характерные для Hashtable.

  • Каждое значение HashMapEntry s равно volatile , обеспечивая тем самым высокую однородность зерна для предполагаемых изменений и последующих считываний; каждое чтение отражает последнее завершенное обновление

  • Итераторы и перечисления являются отказоустойчивыми - отражают состояние в некоторый момент с момента создания итератора / перечисления; это позволяет одновременно считывать и модифицировать за счет снижения согласованности. Они не генерируют ConcurrentModificationException. Однако итераторы предназначены для использования только одним потоком за один раз.

  • Как и Hashtable, но, в отличие от HashMap, этот класс не позволяет использовать null в качестве ключа или значения.

public static void main(String[] args) {

    //HashMap<String, Integer> hash = new HashMap<String, Integer>();
    Hashtable<String, Integer> hash = new Hashtable<String, Integer>();
    //ConcurrentHashMap<String, Integer> hash = new ConcurrentHashMap<>();

    new Thread() {
        @Override public void run() {
            try {
                for (int i = 10; i < 20; i++) {
                    sleepThread(1);
                    System.out.println("T1 :- Key"+i);
                    hash.put("Key"+i, i);
                }
                System.out.println( System.identityHashCode( hash ) );
            } catch ( Exception e ) {
                e.printStackTrace();
            }
        }
    }.start();
    new Thread() {
        @Override public void run() {
            try {
                sleepThread(5);
                // ConcurrentHashMap  traverse using Iterator, Enumeration is Fail-Safe.

                // Hashtable traverse using Enumeration is Fail-Safe, Iterator is Fail-Fast.
                for (Enumeration<String> e = hash.keys(); e.hasMoreElements(); ) {
                    sleepThread(1);
                    System.out.println("T2 : "+ e.nextElement());
                }

                // HashMap traverse using Iterator, Enumeration is Fail-Fast.
                /*
                for (Iterator< Entry<String, Integer> > it = hash.entrySet().iterator(); it.hasNext(); ) {
                    sleepThread(1);
                    System.out.println("T2 : "+ it.next());
                    // ConcurrentModificationException at java.util.Hashtable$Enumerator.next
                }
                */

                /*
                Set< Entry<String, Integer> > entrySet = hash.entrySet();
                Iterator< Entry<String, Integer> > it = entrySet.iterator();
                Enumeration<Entry<String, Integer>> entryEnumeration = Collections.enumeration( entrySet );
                while( entryEnumeration.hasMoreElements() ) {
                    sleepThread(1);
                    Entry<String, Integer> nextElement = entryEnumeration.nextElement();
                    System.out.println("T2 : "+ nextElement.getKey() +" : "+ nextElement.getValue() );
                    //java.util.ConcurrentModificationException at java.util.HashMap$HashIterator.nextNode
                    //                                          at java.util.HashMap$EntryIterator.next
                    //                                          at java.util.Collections$3.nextElement
                }
                */
            } catch ( Exception e ) {
                e.printStackTrace();
            }
        }
    }.start();

    Map<String, String> unmodifiableMap = Collections.unmodifiableMap( map );
    try {
        unmodifiableMap.put("key4", "unmodifiableMap");
    } catch (java.lang.UnsupportedOperationException e) {
        System.err.println("UnsupportedOperationException : "+ e.getMessage() );
    }
}
static void sleepThread( int sec ) {
    try {
        Thread.sleep( 1000 * sec );
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

« Нулевые ключи и нулевые значения

HashMap допускает максимум один нулевой ключ и любое количество нулевых значений. Где, поскольку Hashtable не допускает даже один нулевой ключ и нулевое значение, если ключ или значение null, то он генерирует исключение NullPointerException. * ** 1 174 +1175 * * Пример 1 176 ** * 1 178

« Синхронизировано, Потокобезопасен

Hashtable внутренне синхронизировано. Поэтому очень безопасно использовать Hashtable в многопоточных приложениях. Где, как HashMap не внутренне синхронизированы. Поэтому использование HashMap в многопоточных приложениях без внешней синхронизации небезопасно. Вы можете внешне синхронизировать HashMap, используя метод Collections.synchronizedMap().

« Производительность

Поскольку Hashtable является внутренней синхронизацией, это делает Hashtable немного медленнее, чем HashMap.


@ See

17 голосов
/ 03 сентября 2008

Для многопоточных приложений вы часто можете использовать ConcurrentHashMap - зависит от ваших требований к производительности.

15 голосов
/ 27 августа 2014

1. Hashmap и HashTable оба хранят ключ и значение.

2. Hashmap может хранить один ключ как null. Hashtable не может хранить null.

3. HashMap не синхронизирован, но Hashtable синхронизирован.

4. HashMap можно синхронизировать с Collection.SyncronizedMap(map)

Map hashmap = new HashMap();

Map map = Collections.SyncronizedMap(hashmap);
15 голосов
/ 04 мая 2016

Помимо уже упомянутых различий, следует отметить, что, начиная с Java 8, HashMap динамически заменяет узлы (связанный список), используемые в каждом сегменте, на TreeNodes (красно-черное дерево), так что даже в случае коллизий с высоким хеш существует, наихудший случай при поиске равен

O (log (n)) для HashMap Vs O (n) в Hashtable.

* Вышеупомянутое улучшение еще не применено к Hashtable, но только к HashMap, LinkedHashMap и ConcurrentHashMap.

К вашему сведению,

  • TREEIFY_THRESHOLD = 8: если корзина содержит более 8 узлов, связанный список преобразуется в сбалансированное дерево.
  • UNTREEIFY_THRESHOLD = 6: когда область памяти становится слишком маленькой (из-за удаления или изменения размера), дерево преобразуется обратно в связанный список.
...