Java HashMap est l’une des classes de collection les plus populaires en Java. Java HashMap est une implémentation basée sur une table de hachage. HashMap en Java étend la classe AbstractMap qui implémente l’interface Map.
Java HashMap
Quelques points importants à propos de HashMap en Java sont les suivants;
- Java HashMap permet une clé null et des valeurs null.
- HashMap n’est pas une collection ordonnée. Vous pouvez itérer sur les entrées de HashMap à travers l’ensemble des clés, mais elles ne sont pas garanties d’être dans l’ordre de leur ajout à HashMap.
- HashMap est presque similaire à Hashtable, sauf qu’il n’est pas synchronisé et autorise des clés et des valeurs null.
- HashMap utilise sa classe interne Node<K, V> pour stocker les entrées de la carte.
- HashMap stocke les entrées dans plusieurs listes simplement chaînées, appelées seaux ou bacs. Le nombre par défaut de bacs est 16 et il est toujours une puissance de 2.
- HashMap utilise les méthodes hashCode() et equals() sur les clés pour les opérations get et put. Ainsi, l’objet clé de HashMap doit fournir une bonne implémentation de ces méthodes. C’est la raison pour laquelle les classes immuables sont mieux adaptées pour les clés, par exemple String et Integer.
- Java HashMap n’est pas thread-safe, pour un environnement multithread, vous devriez utiliser la classe ConcurrentHashMap ou obtenir une carte synchronisée en utilisant la méthode
Collections.synchronizedMap()
.
Constructeurs de HashMap Java
La classe HashMap de Java propose quatre constructeurs.
- public HashMap(): Le constructeur de HashMap le plus couramment utilisé. Ce constructeur créera une HashMap vide avec une capacité initiale par défaut de 16 et un facteur de charge de 0,75
- public HashMap(int initialCapacity): Ce constructeur de HashMap est utilisé pour spécifier la capacité initiale et le facteur de charge de 0,75. Cela est utile pour éviter le ré-hachage si vous connaissez le nombre de mappages à stocker dans la HashMap.
- public HashMap(int initialCapacity, float loadFactor): Ce constructeur de HashMap créera une HashMap vide avec une capacité initiale et un facteur de charge spécifiés. Vous pouvez l’utiliser si vous connaissez le nombre maximum de mappages à stocker dans HashMap. Dans les scénarios courants, vous devriez éviter cela car un facteur de charge de 0,75 offre un bon compromis entre l’espace et le coût temporel.
- public HashMap(Map<? extends K, ? extends V> m): Crée une Map ayant les mêmes mappages que la carte spécifiée et avec un facteur de charge de 0,75
Exemple de constructeurs de HashMap Java
Le fragment de code ci-dessous montre un exemple de HashMap utilisant tous les constructeurs ci-dessus.
Map<String, String> map1 = new HashMap<>();
Map<String, String> map2 = new HashMap<>(2^5);
Map<String, String> map3 = new HashMap<>(32,0.80f);
Map<String,String> map4 = new HashMap<>(map1);
Les méthodes de HashMap Java
Jetons un coup d’œil aux méthodes importantes de HashMap en Java.
- public void clear(): Cette méthode de HashMap supprimera toutes les correspondances, et la HashMap deviendra vide.
- public boolean containsKey(Object key): Cette méthode renvoie ‘true’ si la clé existe, sinon elle renverra ‘false’.
- public boolean containsValue(Object value): Cette méthode de HashMap renvoie true si la valeur existe, sinon false.
- public Set<Map.Entry<K,V>> entrySet(): Cette méthode renvoie une vue Set des correspondances de HashMap. Cet ensemble est soutenu par la carte, donc les modifications de la carte se reflètent dans l’ensemble, et vice versa.
- public V get(Object key): Renvoie la valeur associée à la clé spécifiée, ou null s’il n’y a pas de correspondance pour la clé.
- public boolean isEmpty(): Une méthode utilitaire renvoyant true s’il n’y a aucune correspondance clé-valeur présente.
- public Set<K> keySet(): Renvoie une vue Set des clés contenues dans cette carte. L’ensemble est soutenu par la carte, donc les modifications de la carte se reflètent dans l’ensemble, et vice versa.
- public V put(K key, V value): Associe la valeur spécifiée à la clé spécifiée dans cette carte. Si la carte contenait précédemment une correspondance pour la clé, la vieille valeur est remplacée.
- public void putAll(Map extends K, ? extends V> m): Copie toutes les correspondances de la carte spécifiée vers cette carte. Ces correspondances remplaceront toutes les correspondances que cette carte avait pour l’une des clés actuellement dans la carte spécifiée.
- public V remove(Object key): Supprime la correspondance pour la clé spécifiée de cette carte si elle est présente.
- public int size(): Renvoie le nombre de correspondances clé-valeur dans cette carte.
- public Collection
values() : Renvoie une vue de collection des valeurs contenues dans cette carte. La collection est sauvegardée par la carte, donc les modifications apportées à la carte se reflètent dans la collection, et vice versa.
Il existe de nombreuses nouvelles méthodes dans HashMap introduites en Java 8.
- public V computeIfAbsent(K key, Function super K, ? extends V> mappingFunction): Si la clé spécifiée n’est pas déjà associée à une valeur (ou est associée à null), cette méthode tente de calculer sa valeur en utilisant la fonction de mappage donnée et l’entre dans la HashMap à moins de Null.
- public V computeIfPresent(K key, BiFunction super K, ? super V, ? extends V> remappingFunction): Si la valeur pour la clé spécifiée est présente et non nulle, tente de calculer une nouvelle correspondance donnée par la clé et sa valeur actuellement mappée.
- public V compute(K key, BiFunction super K, ? super V, ? extends V> remappingFunction): Cette méthode de HashMap tente de calculer une correspondance pour la clé spécifiée et sa valeur actuellement mappée.
- public void forEach(BiConsumer<? super K, ? super V> action): Cette méthode exécute l’action donnée pour chaque entrée de cette carte.
- public V getOrDefault(Object key, V defaultValue): Identique à get, sauf que defaultValue est retourné si aucune correspondance n’est trouvée pour la clé spécifiée.
- public V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction): Si la clé spécifiée n’est pas déjà associée à une valeur ou est associée à null, elle est associée à la valeur non null donnée. Sinon, remplace la valeur associée par les résultats de la fonction de remappage donnée, ou la supprime si le résultat est null.
- public V putIfAbsent(K key, V value): Si la clé spécifiée n’est pas déjà associée à une valeur (ou est associée à null), elle est associée à la valeur donnée et null est renvoyé, sinon la valeur actuelle est renvoyée.
- public boolean remove(Object key, Object value): Supprime l’entrée pour la clé spécifiée uniquement si elle est actuellement associée à la valeur spécifiée.
- public boolean replace(K key, V oldValue, V newValue): Remplace l’entrée pour la clé spécifiée uniquement si elle est actuellement associée à la valeur spécifiée.
- public V replace(K key, V value): Remplace l’entrée pour la clé spécifiée uniquement si elle est actuellement associée à une valeur.
- public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function): Remplace la valeur de chaque entrée par le résultat de l’invocation de la fonction donnée sur cette entrée.
Exemple de HashMap Java
Voici un programme Java simple pour les méthodes couramment utilisées de HashMap.
package com.journaldev.examples;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
public class HashMapExample {
public static void main(String[] args) {
Map<String, String> map = new HashMap<>();
map.put("1", "1"); // put example
map.put("2", "2");
map.put("3", "3");
map.put("4", null); // null value
map.put(null, "100"); // null key
String value = map.get("3"); // get example
System.out.println("Key = 3, Value = " + value);
value = map.getOrDefault("5", "Default Value");
System.out.println("Key = 5, Value=" + value);
boolean keyExists = map.containsKey(null);
boolean valueExists = map.containsValue("100");
System.out.println("keyExists=" + keyExists + ", valueExists=" + valueExists);
Set<Entry<String, String>> entrySet = map.entrySet();
System.out.println(entrySet);
System.out.println("map size=" + map.size());
Map<String, String> map1 = new HashMap<>();
map1.putAll(map);
System.out.println("map1 mappings= " + map1);
String nullKeyValue = map1.remove(null);
System.out.println("map1 null key value = " + nullKeyValue);
System.out.println("map1 after removing null key = " + map1);
Set<String> keySet = map.keySet();
System.out.println("map keys = " + keySet);
Collection<String> values = map.values();
System.out.println("map values = " + values);
map.clear();
System.out.println("map is empty=" + map.isEmpty());
}
}
Voici la sortie du programme exemple de HashMap Java ci-dessus.
Key = 3, Value = 3
Key = 5, Value=Default Value
keyExists=true, valueExists=true
[null=100, 1=1, 2=2, 3=3, 4=null]
map size=5
map1 mappings= {null=100, 1=1, 2=2, 3=3, 4=null}
map1 null key value = 100
map1 after removing null key = {1=1, 2=2, 3=3, 4=null}
map keys = [null, 1, 2, 3, 4]
map values = [100, 1, 2, 3, null]
map is empty=true
Comment fonctionne HashMap en Java?
HashMap en java utilise sa classe interne Node<K,V> pour stocker les correspondances. HashMap fonctionne sur un algorithme de hachage et utilise les méthodes hashCode() et equals() sur la clé pour les opérations get et put. HashMap utilise une liste chaînée simple pour stocker les éléments, appelés bacs ou seaux. Lorsque nous appelons la méthode put, le hashCode de la clé est utilisé pour déterminer le bac qui sera utilisé pour stocker la correspondance. Une fois le bac identifié, le hashCode est utilisé pour vérifier s’il existe déjà une clé avec le même hashCode ou non. S’il existe une clé existante avec le même hashCode, alors la méthode equals() est utilisée sur la clé. Si equals retourne vrai, alors la valeur est écrasée, sinon une nouvelle correspondance est faite dans ce bac de liste chaînée simple. S’il n’y a pas de clé avec le même hashCode, alors la correspondance est insérée dans le bac. Pour l’opération get de HashMap, encore une fois, le hashCode de la clé est utilisé pour déterminer le bac dans lequel chercher la valeur. Une fois le bac identifié, les entrées sont parcourues pour trouver l’entrée en utilisant le hashCode et la méthode equals. Si une correspondance est trouvée, la valeur est renvoyée, sinon null est renvoyé. Il y a beaucoup plus de choses impliquées, comme l’algorithme de hachage pour obtenir le bac pour la clé, le rehachage des correspondances, etc. Mais pour notre travail, il suffit de se rappeler que les opérations de HashMap fonctionnent sur la clé et une bonne implémentation des méthodes hashCode et equals est nécessaire pour éviter un comportement indésirable. L’image ci-dessous montre l’explication des opérations get et put. Lecture recommandée: L’importance des méthodes hashCode et equals en Java
Java HashMap Load Factor
Le facteur de charge est utilisé pour déterminer quand la table de hachage (HashMap) sera réorganisée et la taille du seau sera augmentée. La valeur par défaut du seau ou de la capacité est de 16 et le facteur de charge est de 0,75. Le seuil de réorganisation est calculé en multipliant la capacité par le facteur de charge. Ainsi, la valeur de seuil par défaut sera de 12. Donc, lorsque la table de hachage aura plus de 12 mappages, elle sera réorganisée et le nombre de bacs sera augmenté à la puissance suivante de 2, c’est-à-dire 32. Notez que la capacité de la table de hachage est toujours une puissance de 2. Le facteur de charge par défaut de 0,75 offre un bon compromis entre l’espace et la complexité temporelle. Cependant, vous pouvez le régler sur différentes valeurs en fonction de vos besoins. Si vous souhaitez économiser de l’espace, vous pouvez augmenter sa valeur à 0,80 ou 0,90, mais les opérations get/put prendront alors plus de temps.
Java HashMap keySet
La méthode keySet de Java HashMap renvoie la vue Set des clés dans la table de hachage. Cette vue Set est soutenue par la table de hachage et tout changement dans la table de hachage se reflète dans le Set et vice versa. Ci-dessous, un programme simple illustrant des exemples de keySet de HashMap et la façon de procéder si vous souhaitez un keySet qui n’est pas soutenu par la table de hachage.
package com.journaldev.examples;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class HashMapKeySetExample {
public static void main(String[] args) {
Map<String, String> map = new HashMap<>();
map.put("1", "1");
map.put("2", "2");
map.put("3", "3");
Set<String> keySet = map.keySet();
System.out.println(keySet);
map.put("4", "4");
System.out.println(keySet); // keySet is backed by Map
keySet.remove("1");
System.out.println(map); // map is also modified
keySet = new HashSet<>(map.keySet()); // copies the key to new Set
map.put("5", "5");
System.out.println(keySet); // keySet is not modified
}
}
La sortie du programme ci-dessus clarifiera que le keySet est soutenu par la table de hachage.
[1, 2, 3]
[1, 2, 3, 4]
{2=2, 3=3, 4=4}
[2, 3, 4]
Valeurs de Java HashMap
La méthode des valeurs de Java HashMap renvoie une vue Collection des valeurs dans la carte. Cette collection est sauvegardée par HashMap, donc tout changement dans HashMap se reflétera dans la collection de valeurs et vice versa. Un exemple simple ci-dessous confirme ce comportement de la collection de valeurs de HashMap.
package com.journaldev.examples;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
public class HashMapValuesExample {
public static void main(String[] args) {
Map<String, String> map = new HashMap<>();
map.put("1", "1");
map.put("2", "2");
map.put("3", null);
map.put("4", null);
map.put(null, "100");
Collection<String> values = map.values();
System.out.println("map values = " + values);
map.remove(null);
System.out.println("map values after removing null key = " + values);
map.put("5", "5");
System.out.println("map values after put = " + values);
System.out.println(map);
values.remove("1"); // changing values collection
System.out.println(map); // updates in map too
}
}
La sortie du programme ci-dessus est la suivante.
map values = [100, 1, 2, null, null]
map values after removing null key = [1, 2, null, null]
map values after put = [1, 2, null, null, 5]
{1=1, 2=2, 3=null, 4=null, 5=5}
{2=2, 3=null, 4=null, 5=5}
Ensemble d’entrées de Java HashMap
La méthode entrySet de Java HashMap renvoie la vue Set des mappages. Cet entrySet est sauvegardé par HashMap, donc tout changement dans la carte se reflète dans l’ensemble d’entrées et vice versa. Jetez un coup d’œil au programme exemple ci-dessous pour un exemple de entrySet de HashMap.
package com.journaldev.examples;
import java.util.AbstractMap;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
public class HashMapEntrySetExample {
public static void main(String[] args) {
Map<String, String> map = new HashMap<>();
map.put("1", "1");
map.put("2", null);
map.put(null, "100");
Set<Entry<String,String>> entrySet = map.entrySet();
Iterator<Entry<String, String>> iterator = entrySet.iterator();
Entry<String, String> next = null;
System.out.println("map before processing = "+map);
System.out.println("entrySet before processing = "+entrySet);
while(iterator.hasNext()){
next = iterator.next();
System.out.println("Processing on: "+next.getValue());
if(next.getKey() == null) iterator.remove();
}
System.out.println("map after processing = "+map);
System.out.println("entrySet after processing = "+entrySet);
Entry<String, String> simpleEntry = new AbstractMap.SimpleEntry<String, String>("1","1");
entrySet.remove(simpleEntry);
System.out.println("map after removing Entry = "+map);
System.out.println("entrySet after removing Entry = "+entrySet);
}
}
Voici la sortie produite par le programme ci-dessus.
map before processing = {null=100, 1=1, 2=null}
entrySet before processing = [null=100, 1=1, 2=null]
Processing on: 100
Processing on: 1
Processing on: null
map after processing = {1=1, 2=null}
entrySet after processing = [1=1, 2=null]
map after removing Entry = {2=null}
entrySet after removing Entry = [2=null]
Java HashMap putIfAbsent
A simple example for HashMap putIfAbsent method introduced in Java 8.
package com.journaldev.examples;
import java.util.HashMap;
import java.util.Map;
public class HashMapPutIfAbsentExample {
public static void main(String[] args) {
Map<String, String> map = new HashMap<>();
map.put("1", "1");
map.put("2", null);
map.put(null, "100");
System.out.println("map before putIfAbsent = "+map);
String value = map.putIfAbsent("1", "4");
System.out.println("map after putIfAbsent = "+map);
System.out.println("putIfAbsent returns: "+value);
System.out.println("map before putIfAbsent = "+map);
value = map.putIfAbsent("3", "3");
System.out.println("map after putIfAbsent = "+map);
System.out.println("putIfAbsent returns: "+value);
}
}
La sortie du programme ci-dessus est la suivante;
map before putIfAbsent = {null=100, 1=1, 2=null}
map after putIfAbsent = {null=100, 1=1, 2=null}
putIfAbsent returns: 1
map before putIfAbsent = {null=100, 1=1, 2=null}
map after putIfAbsent = {null=100, 1=1, 2=null, 3=3}
putIfAbsent returns: null
Java HashMap forEach
La méthode forEach de HashMap est introduite en Java 8. C’est une méthode très utile pour effectuer l’action donnée pour chaque entrée dans la carte jusqu’à ce que toutes les entrées aient été traitées ou que l’action lance une exception.
package com.journaldev.examples;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiConsumer;
public class HashMapForEachExample {
public static void main(String[] args) {
Map map = new HashMap<>();
map.put("1", "1");
map.put("2", null);
map.put(null, "100");
BiConsumer action = new MyBiConsumer();
map.forEach(action);
//exemple d'expression lambda
System.out.println("\nHashMap forEach lambda example\n");
map.forEach((k,v) -> {System.out.println("Key = "+k+", Value = "+v);});
}
}
class MyBiConsumer implements BiConsumer {
@Override
public void accept(String t, String u) {
System.out.println("Key = " + t);
System.out.println("Processing on value = " + u);
}
}
La sortie du programme d’exemple forEach de HashMap ci-dessus est :
Key = null
Processing on value = 100
Key = 1
Processing on value = 1
Key = 2
Processing on value = null
HashMap forEach lambda example
Key = null, Value = 100
Key = 1, Value = 1
Key = 2, Value = null
Java HashMap replaceAll
La méthode replaceAll de HashMap peut être utilisée pour remplacer la valeur de chaque entrée par le résultat de l’invocation de la fonction donnée sur cette entrée. Cette méthode est ajoutée en Java 8 et nous pouvons utiliser des expressions lambda pour cet argument de méthode.
package com.journaldev.examples;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiFunction;
public class HashMapReplaceAllExample {
public static void main(String[] args) {
Map map = new HashMap<>();
map.put("1", "1");
map.put("2", "2");
map.put(null, "100");
System.out.println("map before replaceAll = " + map);
BiFunction function = new MyBiFunction();
map.replaceAll(function);
System.out.println("map after replaceAll = " + map);
// replaceAll en utilisant des expressions lambda
map.replaceAll((k, v) -> {
if (k != null) return k + v;
else return v;});
System.out.println("map after replaceAll lambda expression = " + map);
}
}
class MyBiFunction implements BiFunction {
@Override
public String apply(String t, String u) {
if (t != null)
return t + u;
else
return u;
}
}
La sortie du programme replaceAll de HashMap ci-dessus est :
map before replaceAll = {null=100, 1=1, 2=2}
map after replaceAll = {null=100, 1=11, 2=22}
map after replaceAll lambda example = {null=100, 1=111, 2=222}
Java HashMap computeIfAbsent
La méthode computeIfAbsent de HashMap calcule la valeur uniquement si la clé n’est pas présente dans la carte. Après avoir calculé la valeur, elle est placée dans la carte si elle n’est pas nulle.
package com.journaldev.examples;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
public class HashMapComputeIfAbsent {
public static void main(String[] args) {
Map map = new HashMap<>();
map.put("1", "10");
map.put("2", "20");
map.put(null, "100");
Function function = new MyFunction();
map.computeIfAbsent("3", function); //key not present
map.computeIfAbsent("2", function); //key already present
//méthode lambda
map.computeIfAbsent("4", v -> {return v;});
map.computeIfAbsent("5", v -> {return null;}); //null value won't get inserted
System.out.println(map);
}
}
class MyFunction implements Function {
@Override
public String apply(String t) {
return t;
}
}
La sortie du programme ci-dessus est :
{null=100, 1=10, 2=20, 3=3, 4=4}
Java HashMap computeIfPresent
La méthode computeIfPresent de Java HashMap recale la valeur si la clé spécifiée est présente et que la valeur n’est pas nulle. Si la fonction renvoie null, le mappage est supprimé.
package com.journaldev.examples;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiFunction;
public class HashMapComputeIfPresentExample {
public static void main(String[] args) {
Map<String, String> map = new HashMap<>();
map.put("1", "10");
map.put("2", "20");
map.put(null, "100");
map.put("10", null);
System.out.println("map before computeIfPresent = " + map);
BiFunction<String, String, String> function = new MyBiFunction1();
for (String key : map.keySet()) {
map.computeIfPresent(key, function);
}
System.out.println("map after computeIfPresent = " + map);
map.computeIfPresent("1", (k,v) -> {return null;}); // mapping will be removed
System.out.println("map after computeIfPresent = " + map);
}
}
class MyBiFunction1 implements BiFunction<String, String, String> {
@Override
public String apply(String t, String u) {
return t + u;
}
}
La sortie produite par l’exemple computeIfPresent de HashMap est;
map before computeIfPresent = {null=100, 1=10, 2=20, 10=null}
map after computeIfPresent = {null=null100, 1=110, 2=220, 10=null}
map after computeIfPresent = {null=null100, 2=220, 10=null}
Java HashMap compute
Si vous souhaitez appliquer une fonction sur tous les mappages en fonction de sa clé et de sa valeur, la méthode compute doit être utilisée. Si aucun mappage n’existe et que cette méthode est utilisée, la valeur sera nulle pour la fonction compute.
package com.journaldev.examples;
import java.util.HashMap;
import java.util.Map;
public class HashMapComputeExample {
public static void main(String[] args) {
Map<String, String> map = new HashMap<>();
map.put("1", "1");
map.put("2", "2");
map.put(null, "10");
map.put("10", null);
System.out.println("map before compute = "+map);
for (String key : map.keySet()) {
map.compute(key, (k,v) -> {return k+v;});
}
map.compute("5", (k,v) -> {return k+v;}); //key not present, v = null
System.out.println("map after compute = "+map);
}
}
La sortie de l’exemple compute de HashMap est;
map before compute = {null=10, 1=1, 2=2, 10=null}
map after compute = {null=null10, 1=11, 2=22, 5=5null, 10=10null}
Java HashMap merge
Si la clé spécifiée n’est pas présente ou est associée à null, alors elle est associée à la valeur non nulle donnée. Sinon, remplace la valeur associée par les résultats de la fonction de remappage donnée, ou supprime si le résultat est null.
package com.journaldev.examples;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
public class HashMapMergeExample {
public static void main(String[] args) {
Map map = new HashMap<>();
map.put("1", "1");
map.put("2", "2");
map.put(null, "10");
map.put("10", null);
for (Entry entry : map.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
//merge lance une NullPointerException si la clé ou la valeur est null
if(key != null && value != null)
map.merge(entry.getKey(), entry.getValue(),
(k, v) -> {return k + v;});
}
System.out.println(map);
map.merge("5", "5", (k, v) -> {return k + v;}); // key not present
System.out.println(map);
map.merge("1", "1", (k, v) -> {return null;}); // method return null, so remove
System.out.println(map);
}
}
La sortie du programme ci-dessus est;
{null=10, 1=11, 2=22, 10=null}
{null=10, 1=11, 2=22, 5=5, 10=null}
{null=10, 2=22, 5=5, 10=null}
C’est tout pour HashMap en Java, j’espère qu’aucun élément important n’a été omis. Partagez-le également avec d’autres si vous l’avez apprécié. Référence: Documentation de l’API
Source:
https://www.digitalocean.com/community/tutorials/java-hashmap