[java] Différences entre HashMap et Hashtable?


14 Answers

Notez que beaucoup de réponses indiquent que Hashtable est synchronisé. En pratique, cela vous achète très peu. La synchronisation sur les méthodes accesseur / mutator arrêtera deux threads en ajoutant ou en supprimant simultanément de la map, mais dans le monde réel, vous aurez souvent besoin d'une synchronisation supplémentaire.

Un idiome très commun est de "vérifier puis mettre" - c.-à-d. Chercher une entrée dans la carte, et l'ajouter si elle n'existe pas déjà. Ce n'est en aucun cas une opération atomique que vous utilisiez Hashtable ou HashMap.

Un HashMap synchronisé de manière équivalente peut être obtenu par:

Collections.synchronizedMap(myMap);

Mais pour implémenter correctement cette logique, vous avez besoin d' une synchronisation supplémentaire du formulaire:

synchronized(myMap) {
    if (!myMap.containsKey("tomato"))
        myMap.put("tomato", "red");
}

Même itérer sur les entrées d'un Hashtable (ou un HashMap obtenu par Collections.synchronizedMap) n'est pas thread-safe sauf si vous empêchez également la carte d'être modifiée par une synchronisation supplémentaire.

Les implémentations de l'interface ConcurrentMap (par exemple ConcurrentHashMap ) résolvent certains de ces problèmes en incluant des sémantiques check-then-act sécurisées par le thread telles que:

ConcurrentMap.putIfAbsent(key, value);
Question

Quelles sont les différences entre un HashMap et un Hashtable en Java?

Quel est le plus efficace pour les applications non-threaded?




Il y a beaucoup de bonnes réponses déjà postées. J'ajoute quelques nouveaux points et je le résume.

HashMap et Hashtable sont tous deux utilisés pour stocker des données sous forme de clé et de valeur . Les deux utilisent la technique de hachage pour stocker des clés uniques. Mais il existe de nombreuses différences entre les classes HashMap et Hashtable indiquées ci-dessous.

HashMap

1) HashMap n'est pas synchronisé. Il n'est pas thread-safe et ne peut pas être partagé entre plusieurs threads sans code de synchronisation approprié.
2) HashMap autorise une clé nulle et plusieurs valeurs nulles.
3) HashMap est une nouvelle classe introduite dans JDK 1.2.
4) HashMap est rapide.
5) Nous pouvons synchroniser le HashMap en appelant ce code
Map m = Collections.synchronizedMap(HashMap);
6) HashMap est traversé par Iterator.
7) Iterator dans HashMap est fail-fast.
8) HashMap hérite de la classe AbstractMap.

Hashtable

1) Hashtable est synchronisé. Il est thread-safe et peut être partagé avec de nombreux threads.
2) Hashtable n'autorise aucune clé ou valeur nulle.
3) Hashtable est une classe héritée.
4) Hashtable est lent.
5) Hashtable est synchronisé en interne et ne peut pas être désynchronisé.
6) Hashtable est traversé par Enumerator et Iterator.
7) Enumérateur dans Hashtable n'est pas fail-fast.
8) Hashtable hérite de la classe Dictionary.

En savoir plus Quelle est la différence entre HashMap et Hashtable en Java?




Il y a 5 différenciations de base avec HashTable et HashMaps.

  1. Maps vous permet d'itérer et d'extraire des clés, des valeurs et les deux paires clé-valeur, où HashTable n'a pas toutes ces fonctionnalités.
  2. Dans Hashtable, il y a une fonction contains (), ce qui est très déroutant à utiliser. Parce que la signification de contient est légèrement déviante. Que cela signifie contient une clé ou contient de la valeur? difficile à comprendre. Même chose dans Maps, nous avons les fonctions ContainsKey () et ContainsValue (), qui sont très faciles à comprendre.
  3. Dans hashmap, vous pouvez supprimer un élément en cours d'itération, en toute sécurité. où comme ce n'est pas possible dans les hashtables.
  4. HashTables sont par défaut synchronisés, donc il peut être utilisé avec plusieurs threads facilement. Lorsque les HashMaps ne sont pas synchronisés par défaut, ils peuvent être utilisés avec un seul thread. Mais vous pouvez toujours convertir HashMap en synchronisé en utilisant la fonction synchronisedMap de la classe Utilities de Collections (Map m).
  5. HashTable n'autorisera pas les clés nulles ou les valeurs nulles. Où HashMap autorise une clé nulle et plusieurs valeurs nulles.



Différences entre HashMap et Hashtable en Java:

1) Filetage sûr

  • HashTable est synchronisé en interne.
  • Par conséquent, il est très sûr d'utiliser HashTable dans des applications multi-thread.
  • Où HashMap n'est pas synchronisé en interne.
  • Par conséquent, il est dangereux d'utiliser HashMap dans des applications multi-thread sans synchronisation externe.
  • Vous pouvez synchroniser de manière externe HashMap à l'aide de la méthode Collections.synchronizedMap ().

2) Hérité de

  • Bien que HashMap et HashTable implémentent l'interface Map, ils étendent deux classes différentes.
  • HashMap étend la classe AbstractMap où HashTable étend la classe Dictionary qui est la classe héritée de java.

3) Clés nulles et valeurs nulles

  • HashMap autorise au maximum une clé nulle et n'importe quel nombre de valeurs nulles.
  • Où HashTable n'autorise même pas une seule clé nulle et une valeur nulle.

4) Traversée

  • HashMap renvoie uniquement les itérateurs qui sont utilisés pour traverser les éléments de HashMap.
  • HashTable renvoie Iterator ainsi que Enumeration qui peut être utilisé pour traverser les éléments de HashTable.

5) Fail-Fast Vs Fail-Safe

  • Les itérateurs retournés par HashMap sont de nature rapide, c'est-à-dire qu'ils lancent ConcurrentModificationException si le HashMap est modifié après la création d'Iterator autre que la méthode remove () de l'itérateur.
  • D'un autre côté, les énumérations retournées par le HashTable sont de nature sécurisée, c'est-à-dire qu'elles ne lancent aucune exception si le HashTable est modifié après la création d'Enumeration.

6) Performance

  • Comme HashTable est synchronisé en interne, cela rend HashTable légèrement plus lent que HashMap.

7) Classe Legacy

  • HashTable est une classe héritée.
  • Il est presque considéré comme dû à la dépréciation.
  • Depuis JDK 1.5, ConcurrentHashMap est considéré comme une meilleure option que le HashTable.

8) Membre de Java Collection Framework

  • HashMap est un membre de Java Collection Framework dès le début de son introduction dans JDK 1.2.
  • Mais, HashTable était là avant JDK 1.2. À partir de JDK 1.2, il a été créé pour implémenter l'interface Map, ce qui en fait un membre du framework de collection.

Quel est le plus efficace pour les applications non-threaded?

  • Hashtable est synchronisé, alors que HashMap ne l'est pas.

  • Cela rend HashMap meilleur pour les applications non-threadées , car les objets non synchronisés fonctionnent généralement mieux que ceux synchronisés.




HashMaps gives you freedom of synchronization and debugging is lot more easier




Une Collection - parfois appelée un conteneur - est simplement un objet qui regroupe plusieurs éléments en une seule unité. Collection sont utilisées pour stocker, récupérer, manipuler et communiquer des données agrégées. Un framework de collections W est une architecture unifiée pour représenter et manipuler des collections.

HashMap JDK1.2 et Hashtable JDK1.0 , tous deux sont utilisés pour représenter un groupe d'objets représentés dans la paire <Key, Value> . Chaque paire <Key, Value> est appelée objet Entry . La collection d'entrées est référée par l'objet de HashMap et Hashtable . Les clés d'une collection doivent être uniques ou distinctives. [car ils sont utilisés pour récupérer une valeur mappée une clé particulière. les valeurs d'une collection peuvent être dupliquées.]

« Membre de la Superclasse, Legacy et Collection Framework

Hashtable est une classe héritée introduite dans JDK1.0 , qui est une sous-classe de la classe Dictionary. À partir de JDK1.2 Hashtable est reconfiguré pour implémenter l' interface Map afin de créer un membre de l' JDK1.2 de collecte. HashMap est un membre de Java Collection Framework dès le début de son introduction dans JDK1.2 . HashMap est la sous-classe de la classe 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 { ... }

« Capacité initiale et facteur de charge

La capacité est le nombre de compartiments dans la table de hachage, et la capacité initiale est simplement la capacité au moment où la table de hachage est créée. Notez que la table de hachage est ouverte: dans le cas d'une " collision hash ", un seul compartiment stocke plusieurs entrées, qui doivent être recherchées de manière séquentielle. Le facteur de charge est une mesure de la capacité de la table de hachage à être complète avant que sa capacité soit automatiquement augmentée.

HashMap construit une table de hachage vide avec la capacité initiale par défaut (16) et le facteur de charge par défaut (0.75). Where as Hashtable constructs empty hashtable with a default initial capacity (11) and load factor/fill ratio (0.75).

« Structural modification in case of hash collision

HashMap , Hashtable in case of hash collisions they store the map entries in linked lists. From Java8 for HashMap if hash bucket grows beyond a certain threshold, that bucket will switch from linked list of entries to a balanced tree . which improve worst-case performance from O(n) to O(log n). While converting the list to binary tree, hashcode is used as a branching variable. If there are two different hashcodes in the same bucket, one is considered bigger and goes to the right of the tree and other one to the left. But when both the hashcodes are equal, HashMap assumes that the keys are comparable, and compares the key to determine the direction so that some order can be maintained. It is a good practice to make the keys of HashMap comparable . On adding entries if bucket size reaches TREEIFY_THRESHOLD = 8 convert linked list of entries to a balanced tree, on removing entries less than TREEIFY_THRESHOLD and at most UNTREEIFY_THRESHOLD = 6 will reconvert balanced tree to linked list of entries. Java 8 SRC , stackpost

« Collection-view iteration, Fail-Fast and Fail-Safe

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

Iterator is a fail-fast in nature. ie it throws ConcurrentModificationException if a collection is modified while iterating other than it's own remove() method. Where as Enumeration is fail-safe in nature. It doesn't throw any exceptions if a collection is modified while iterating.

According to Java API Docs, Iterator is always preferred over the Enumeration.

NOTE: The functionality of Enumeration interface is duplicated by the Iterator interface. In addition, Iterator adds an optional remove operation, and has shorter method names. New implementations should consider using Iterator in preference to Enumeration.

In Java 5 introduced ConcurrentMap Interface : ConcurrentHashMap - a highly concurrent, high-performance ConcurrentMap implementation backed by a hash table. This implementation never blocks when performing retrievals and allows the client to select the concurrency level for updates. It is intended as a drop-in replacement for Hashtable : in addition to implementing ConcurrentMap , it supports all of the "legacy" methods peculiar to Hashtable .

  • Each HashMapEntry s value is volatile thereby ensuring fine grain consistency for contended modifications and subsequent reads; each read reflects the most recently completed update

  • Iterators and Enumerations are Fail Safe - reflecting the state at some point since the creation of iterator/enumeration; this allows for simultaneous reads and modifications at the cost of reduced consistency. They do not throw ConcurrentModificationException. However, iterators are designed to be used by only one thread at a time.

  • Like Hashtable but unlike HashMap , this class does not allow null to be used as a key or value.

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();
    }
}

« Null Keys And Null Values

HashMap allows maximum one null key and any number of null values. Where as Hashtable doesn't allow even a single null key and null value, if the key or value null is then it throws NullPointerException. Example

« Synchronized, Thread Safe

Hashtable is internally synchronized. Therefore, it is very much safe to use Hashtable in multi threaded applications. Where as HashMap is not internally synchronized. Therefore, it is not safe to use HashMap in multi threaded applications without external synchronization. You can externally synchronize HashMap using Collections.synchronizedMap() method.

« Performance

As Hashtable is internally synchronized, this makes Hashtable slightly slower than the HashMap .

@See




Hashtable:

Hashtable is a data structure that retains values of key-value pair. It doesn't allow null for both the keys and the values. You will get a NullPointerException if you add null value. It is synchronized. So it comes with its cost. Only one thread can access HashTable at a particular time.

Example :

import java.util.Map;
import java.util.Hashtable;

public class TestClass {

    public static void main(String args[ ]) {
    Map<Integer,String> states= new Hashtable<Integer,String>();
    states.put(1, "INDIA");
    states.put(2, "USA");

    states.put(3, null);    //will throw NullPointerEcxeption at runtime

    System.out.println(states.get(1));
    System.out.println(states.get(2));
//  System.out.println(states.get(3));

    }
}

HashMap:

HashMap is like Hashtable but it also accepts key value pair. It allows null for both the keys and the values. Its performance better is better than HashTable , because it is unsynchronized .

Example:

import java.util.HashMap;
import java.util.Map;

public class TestClass {

    public static void main(String args[ ]) {
    Map<Integer,String> states = new HashMap<Integer,String>();
    states.put(1, "INDIA");
    states.put(2, "USA");

    states.put(3, null);    // Okay
    states.put(null,"UK");

    System.out.println(states.get(1));
    System.out.println(states.get(2));
    System.out.println(states.get(3));

    }
}



1. Hashmap et HashTable stockent la clé et la valeur.

2. Hashmap peut stocker une clé comme null . Hashtable ne peut pas stocker null .

3. HashMap n'est pas synchronisé mais Hashtable est synchronisé.

4. HashMap peut être synchronisé avec Collection.SyncronizedMap(map)

Map hashmap = new HashMap();

Map map = Collections.SyncronizedMap(hashmap);



Cette question est souvent posée en entrevue pour vérifier si le candidat comprend l'utilisation correcte des classes de collecte et est conscient des solutions alternatives disponibles.

  1. La classe HashMap est à peu près équivalente à Hashtable, sauf qu'elle est non synchronisée et autorise les valeurs nulles. (HashMap autorise les valeurs nulles comme clé et valeur alors que Hashtable n'autorise pas les valeurs nulles).
  2. HashMap ne garantit pas que l'ordre de la carte restera constant dans le temps.
  3. HashMap n'est pas synchronisé alors que Hashtable est synchronisé.
  4. Iterator dans HashMap est fail-safe alors que l'énumérateur de Hashtable ne l'est pas et lance ConcurrentModificationException si tout autre Thread modifie la structure de manière structurelle en ajoutant ou supprimant tout élément sauf la méthode remove () de Iterator. Mais ceci n'est pas un comportement garanti et sera fait par JVM au meilleur effort.

Note sur quelques termes importants

  1. Synchronisé signifie qu'un seul thread peut modifier une table de hachage à un moment donné. Fondamentalement, cela signifie que tout thread avant d'effectuer une mise à jour sur une hashtable devra acquérir un verrou sur l'objet tandis que d'autres attendront que le verrou soit libéré.
  2. Fail-safe est pertinent dans le contexte des itérateurs. Si un itérateur a été créé sur un objet de collection et qu'un autre thread essaie de modifier l'objet de collection "structurellement", une exception de modification simultanée sera levée. Il est possible que d'autres threads invoquent la méthode "set" car elle ne modifie pas la collection "structurellement". Cependant, si avant d'appeler "set", la collection a été modifiée structurellement, "IllegalArgumentException" sera levé.
  3. La modification structurelle signifie la suppression ou l'insertion d'un élément qui pourrait effectivement modifier la structure de la carte.

HashMap peut être synchronisé par

Map m = Collections.synchronizeMap(hashMap);

Map fournit des vues Collection au lieu de la prise en charge directe de l'itération via les objets Enumeration. Les vues de collection améliorent considérablement l'expressivité de l'interface, comme indiqué plus loin dans cette section. Map vous permet d'itérer sur des clés, des valeurs ou des paires clé-valeur; Hashtable ne fournit pas la troisième option. La carte fournit un moyen sûr de supprimer les entrées au milieu de l'itération; Hashtable n'a pas fait. Enfin, Map corrige une lacune mineure dans l'interface Hashtable. Hashtable a une méthode appelée contains, qui renvoie true si Hashtable contient une valeur donnée. Compte tenu de son nom, vous vous attendez à ce que cette méthode renvoie true si Hashtable contenait une clé donnée, car la clé est le mécanisme d'accès principal d'une table Hashtable. L'interface Map élimine cette source de confusion en renommant la méthode containsValue. En outre, cela améliore la cohérence de l'interface - containsValue met en parallèle containsKey.

L'interface de la carte




  • HashTable est synchronisé, si vous l'utilisez dans un seul thread, vous pouvez utiliser docs.oracle.com/javase/7/docs/api/java/util/HashMap.html , qui est une version non synchronisée. Les objets non synchronisés sont souvent un peu plus performants. Par ailleurs, si plusieurs threads accèdent simultanément à un HashMap, et qu'au moins l'un des threads modifie structurellement la map, il doit être synchronisé de manière externe. Youn peut envelopper une carte non synchronisée dans une carte synchronisée en utilisant:

    Map m = Collections.synchronizedMap(new HashMap(...));
    
  • HashTable ne peut contenir qu'un objet non nul en tant que clé ou valeur. HashMap peut contenir une clé nulle et des valeurs nulles.

  • Les itérateurs retournés par Map sont fail-fast, si la map est structurellement modifiée à tout moment après la création de l'itérateur, de quelque manière que ce soit, à travers la propre méthode remove de l'itérateur, l'itérateur lancera une ConcurrentModificationException . Ainsi, face à une modification simultanée, l'itérateur échoue rapidement et proprement, plutôt que de risquer un comportement arbitraire et non déterministe à un moment indéterminé dans le futur. Alors que les énumérations retournées par les méthodes de Hashtable keys et elements ne sont pas fail-fast.

  • HashTable et HashMap sont membres de Java Collections Framework (depuis Java2 platform v1.2, HashTable a été mis à jour pour implémenter l'interface Map).

  • HashTable est considéré comme du code hérité, la documentation conseille d'utiliser ConcurrentHashMap à la place de Hashtable si une implémentation hautement simultanée thread-safe est souhaitée.

  • HashMap ne garantit pas l'ordre dans lequel les éléments sont retournés. Pour HashTable, je suppose que c'est la même chose mais je ne suis pas tout à fait sûr, je ne trouve pas de ressource qui énonce clairement cela.




HashTable est une classe héritée dans le jdk qui ne devrait plus être utilisée. Remplacez les utilisations avec ConcurrentHashMap . Si vous n'avez pas besoin de sécurité de thread, utilisez HashMap qui n'est pas threadsafe mais plus rapide et utilise moins de mémoire.




Une autre différence clé entre hashtable et hashmap est que Iterator dans HashMap est fail-fast alors que l'énumérateur de Hashtable ne l'est pas et lance ConcurrentModificationException si n'importe quel autre Thread modifie structurellement la map en ajoutant ou supprimant n'importe quel élément sauf la méthode remove () d'Iterator. Mais ce n'est pas un comportement garanti et ce sera fait par JVM sur le meilleur effort. "

Ma source: http://javarevisited.blogspot.com/2010/10/difference-between-hashmap-and.html




Jetez un oeil à ce tableau. Il fournit des comparaisons entre différentes structures de données avec HashMap et Hashtable. La comparaison est précise, claire et facile à comprendre.

Matrice de collection Java




HashMap : HashMap de l'interface Map qui utilise des codes de hachage pour indexer un tableau. Hashtable : Bonjour, 1998 appelé. Ils veulent récupérer leurs API de collections.

Sérieusement, vous feriez mieux de rester loin de Hashtable . Pour les applications monothread, vous n'avez pas besoin de la surcharge supplémentaire de synchronisation. Pour les applications hautement concurrentes, la synchronisation paranoïaque peut entraîner la famine, des interblocages ou des pauses de récupération de place inutiles. Comme Tim Howland l'a fait remarquer, vous pouvez utiliser ConcurrentHashMap place.




Pour les applications avec filetage, vous pouvez souvent vous en sortir avec ConcurrentHashMap, cela dépend de vos exigences de performances.




Related