Java Language
Plans
Recherche…
Introduction
L' interface java.util.Map représente un mappage entre les clés et leurs valeurs. Une carte ne peut pas contenir de clés en double; et chaque clé peut correspondre à au plus une valeur.
Comme Map
est une interface, vous devez instancier une implémentation concrète de cette interface pour pouvoir l'utiliser. Il y a plusieurs implémentations Map
, et les plus utilisées sont java.util.HashMap
et java.util.TreeMap
Remarques
Une carte est un objet qui stocke des clés avec une valeur associée pour chaque clé. Une clé et sa valeur sont parfois appelées une paire clé / valeur ou une entrée . Les cartes fournissent généralement ces fonctionnalités:
- Les données sont stockées dans la carte par paires clé / valeur.
- La carte peut contenir une seule entrée pour une clé particulière. Si une carte contient une entrée avec une clé particulière et que vous essayez de stocker une deuxième entrée avec la même clé, la deuxième entrée remplacera la première. En d'autres termes, cela changera la valeur associée à la clé.
- Les cartes fournissent des opérations rapides pour vérifier si une clé existe dans la carte, pour récupérer la valeur associée à une clé et pour supprimer une paire clé / valeur.
L'implémentation de carte la plus couramment utilisée est HashMap . Cela fonctionne bien avec des clés qui sont des chaînes ou des nombres.
Les cartes simples telles que HashMap ne sont pas ordonnées. Les itérations sur les paires clé / valeur peuvent renvoyer des entrées individuelles dans n'importe quel ordre. Si vous devez parcourir les entrées de carte de manière contrôlée, vous devez regarder les éléments suivants:
Les cartes triées, telles que TreeMap , parcourent les clés dans leur ordre naturel (ou dans un ordre que vous pouvez spécifier, en fournissant un comparateur ). Par exemple, une carte triée utilisant des nombres comme clés devrait pouvoir parcourir ses entrées dans l'ordre numérique.
LinkedHashMap permet de parcourir les entrées dans l'ordre dans lequel elles ont été insérées dans la carte ou dans l'ordre d'accès le plus récent.
Ajouter un élément
- Une addition
Map<Integer, String> map = new HashMap<>();
map.put(1, "First element.");
System.out.println(map.get(1));
Sortie: First element.
- Passer outre
Map<Integer, String> map = new HashMap<>();
map.put(1, "First element.");
map.put(1, "New element.");
System.out.println(map.get(1));
Sortie: New element.
HashMap
est utilisé comme exemple. D'autres implémentations qui implémentent l'interface Map
peuvent également être utilisées.
Ajouter plusieurs éléments
On peut utiliser V put(K key,V value)
:
Associe la valeur spécifiée à la clé spécifiée dans cette carte (opération facultative). Si la carte contenait précédemment un mappage pour la clé, l'ancienne valeur est remplacée par la valeur spécifiée.
String currentVal;
Map<Integer, String> map = new TreeMap<>();
currentVal = map.put(1, "First element.");
System.out.println(currentVal);// Will print null
currentVal = map.put(2, "Second element.");
System.out.println(currentVal); // Will print null yet again
currentVal = map.put(2, "This will replace 'Second element'");
System.out.println(currentVal); // will print Second element.
System.out.println(map.size()); // Will print 2 as key having
// value 2 was replaced.
Map<Integer, String> map2 = new HashMap<>();
map2.put(2, "Element 2");
map2.put(3, "Element 3");
map.putAll(map2);
System.out.println(map.size());
Sortie:
3
Pour ajouter de nombreux éléments, vous pouvez utiliser une classe interne comme celle-ci:
Map<Integer, String> map = new HashMap<>() {{
// This is now an anonymous inner class with an unnamed instance constructor
put(5, "high");
put(4, "low");
put(1, "too slow");
}};
Gardez à l'esprit que la création d'une classe interne anonyme n'est pas toujours efficace et peut entraîner des fuites de mémoire. Dans la mesure du possible, utilisez plutôt un bloc d'initialisation:
static Map<Integer, String> map = new HashMap<>();
static {
// Now no inner classes are created so we can avoid memory leaks
put(5, "high");
put(4, "low");
put(1, "too slow");
}
L'exemple ci-dessus rend la carte statique. Il peut également être utilisé dans un contexte non statique en supprimant toutes les occurrences de static
.
En plus de cela, la plupart des implémentations prennent en charge putAll
, qui peut ajouter toutes les entrées d'une carte à une autre, comme ceci:
another.putAll(one);
Utilisation des méthodes de mappage par défaut de Java 8
Exemples d'utilisation des méthodes par défaut introduites dans l'interface Java 8 dans Map
- Utiliser getOrDefault
Renvoie la valeur associée à la clé ou, si la clé n'est pas présente, renvoie la valeur par défaut
Map<Integer, String> map = new HashMap<>();
map.put(1, "First element");
map.get(1); // => First element
map.get(2); // => null
map.getOrDefault(2, "Default element"); // => Default element
- Utilisation de forEach
Permet d'effectuer l'opération spécifiée dans l'action sur chaque entrée de carte
Map<Integer, String> map = new HashMap<Integer, String>();
map.put(1, "one");
map.put(2, "two");
map.put(3, "three");
map.forEach((key, value) -> System.out.println("Key: "+key+ " :: Value: "+value));
// Key: 1 :: Value: one
// Key: 2 :: Value: two
// Key: 3 :: Value: three
- Utiliser replaceAll
Remplacera par new-value uniquement si la clé est présente
Map<String, Integer> map = new HashMap<String, Integer>();
map.put("john", 20);
map.put("paul", 30);
map.put("peter", 40);
map.replaceAll((key,value)->value+10); //{john=30, paul=40, peter=50}
- Utiliser putIfAbsent
La paire valeur-clé est ajoutée à la carte si la clé n'est pas présente ou associée à la valeur null
Map<String, Integer> map = new HashMap<String, Integer>();
map.put("john", 20);
map.put("paul", 30);
map.put("peter", 40);
map.putIfAbsent("kelly", 50); //{john=20, paul=30, peter=40, kelly=50}
En utilisant remove
Supprime la clé uniquement si elle est associée à la valeur donnée
Map<String, Integer> map = new HashMap<String, Integer>(); map.put("john", 20); map.put("paul", 30); map.put("peter", 40); map.remove("peter",40); //{john=30, paul=40}
En utilisant replace
Si la clé est présente, la valeur est remplacée par une nouvelle valeur. Si la clé n'est pas présente, ne fait rien.
Map<String, Integer> map = new HashMap<String, Integer>();
map.put("john", 20);
map.put("paul", 30);
map.put("peter", 40);
map.replace("peter",50); //{john=20, paul=30, peter=50}
map.replace("jack",60); //{john=20, paul=30, peter=50}
- Utiliser computeIfAbsent
Cette méthode ajoute une entrée dans la carte. la clé est spécifiée dans la fonction et la valeur est le résultat de l'application de la fonction de mappage
Map<String, Integer> map = new HashMap<String, Integer>();
map.put("john", 20);
map.put("paul", 30);
map.put("peter", 40);
map.computeIfAbsent("kelly", k->map.get("john")+10); //{john=20, paul=30, peter=40, kelly=30}
map.computeIfAbsent("peter", k->map.get("john")+10); //{john=20, paul=30, peter=40, kelly=30} //peter already present
- Utiliser computeIfPresent
Cette méthode ajoute une entrée ou modifie une entrée existante dans la carte. Ne fait rien si une entrée avec cette clé n'est pas présente
Map<String, Integer> map = new HashMap<String, Integer>();
map.put("john", 20);
map.put("paul", 30);
map.put("peter", 40);
map.computeIfPresent("kelly", (k,v)->v+10); //{john=20, paul=30, peter=40} //kelly not present
map.computeIfPresent("peter", (k,v)->v+10); //{john=20, paul=30, peter=50} // peter present, so increase the value
- Utiliser le calcul
Cette méthode remplace la valeur d'une clé par la valeur nouvellement calculée
Map<String, Integer> map = new HashMap<String, Integer>();
map.put("john", 20);
map.put("paul", 30);
map.put("peter", 40);
map.compute("peter", (k,v)->v+50); //{john=20, paul=30, peter=90} //Increase the value
- Utiliser la fusion
Ajoute la paire clé-valeur à la carte, si la clé n'est pas présente ou que la valeur de la clé est nulle Remplace la valeur par la nouvelle valeur calculée, si la clé est présente La clé est supprimée si la nouvelle valeur calculée est nulle
Map<String, Integer> map = new HashMap<String, Integer>();
map.put("john", 20);
map.put("paul", 30);
map.put("peter", 40);
//Adds the key-value pair to the map, if key is not present or value for the key is null
map.merge("kelly", 50 , (k,v)->map.get("john")+10); // {john=20, paul=30, peter=40, kelly=50}
//Replaces the value with the newly computed value, if the key is present
map.merge("peter", 50 , (k,v)->map.get("john")+10); //{john=20, paul=30, peter=30, kelly=50}
//Key is removed from the map , if new value computed is null
map.merge("peter", 30 , (k,v)->map.get("nancy")); //{john=20, paul=30, kelly=50}
Effacer la carte
Map<Integer, String> map = new HashMap<>();
map.put(1, "First element.");
map.put(2, "Second element.");
map.put(3, "Third element.");
map.clear();
System.out.println(map.size()); // => 0
En parcourant le contenu d'une carte
Les cartes fournissent des méthodes qui vous permettent d'accéder aux clés, aux valeurs ou aux paires clé-valeur de la carte en tant que collections. Vous pouvez parcourir ces collections. Compte tenu de la carte suivante par exemple:
Map<String, Integer> repMap = new HashMap<>();
repMap.put("Jon Skeet", 927_654);
repMap.put("BalusC", 708_826);
repMap.put("Darin Dimitrov", 715_567);
Itération à travers les clés de la carte:
for (String key : repMap.keySet()) {
System.out.println(key);
}
Impressions:
Darin Dimitrov
Jon Skeet
BalusC
keySet()
fournit les clés de la carte sous la forme d'un Set
. Set
est utilisé car les clés ne peuvent pas contenir de valeurs en double. Itérer à travers l'ensemble donne chaque clé à tour de rôle. Les HashMaps ne sont pas commandés. Dans cet exemple, les clés peuvent être renvoyées dans n'importe quel ordre.
Itération à travers les valeurs de la carte:
for (Integer value : repMap.values()) {
System.out.println(value);
}
Impressions:
715567
927654
708826
values()
renvoie les valeurs de la carte en tant que Collection
. Itérer à travers la collection donne chaque valeur à tour de rôle. Encore une fois, les valeurs peuvent être renvoyées dans n'importe quel ordre.
Itérer à travers les clés et les valeurs ensemble
for (Map.Entry<String, Integer> entry : repMap.entrySet()) {
System.out.printf("%s = %d\n", entry.getKey(), entry.getValue());
}
Impressions:
Darin Dimitrov = 715567
Jon Skeet = 927654
BalusC = 708826
entrySet()
renvoie une collection d'objets Map.Entry
. Map.Entry donne accès à la clé et à la valeur pour chaque entrée.
Fusion, combinaison et composition de cartes
Utilisez putAll
pour mettre chaque membre d'une carte dans une autre. Les clés déjà présentes dans la carte auront leurs valeurs correspondantes écrasées.
Map<String, Integer> numbers = new HashMap<>();
numbers.put("One", 1)
numbers.put("Three", 3)
Map<String, Integer> other_numbers = new HashMap<>();
other_numbers.put("Two", 2)
other_numbers.put("Three", 4)
numbers.putAll(other_numbers)
Cela donne la cartographie suivante en numbers
:
"One" -> 1
"Two" -> 2
"Three" -> 4 //old value 3 was overwritten by new value 4
Si vous souhaitez combiner des valeurs au lieu de les écraser, vous pouvez utiliser Map.merge
, ajouté à Java 8, qui utilise une fonction BiFunction
fournie par l' BiFunction
pour fusionner les valeurs des clés en double. merge
opère sur des clés et des valeurs individuelles, vous devrez donc utiliser une boucle ou Map.forEach
. Ici, nous concaténons des chaînes pour des clés en double:
for (Map.Entry<String, Integer> e : other_numbers.entrySet())
numbers.merge(e.getKey(), e.getValue(), Integer::sum);
//or instead of the above loop
other_numbers.forEach((k, v) -> numbers.merge(k, v, Integer::sum));
Si vous souhaitez appliquer la contrainte, il n'y a pas de clés en double, vous pouvez utiliser une fonction de fusion qui renvoie une AssertionError
:
mapA.forEach((k, v) ->
mapB.merge(k, v, (v1, v2) ->
{throw new AssertionError("duplicate values for key: "+k);}));
Composer la carte <X, Y> et la carte <Y, Z> pour obtenir la carte <X, Z>
Si vous voulez composer deux mappages, vous pouvez le faire comme suit
Map<String, Integer> map1 = new HashMap<String, Integer>();
map1.put("key1", 1);
map1.put("key2", 2);
map1.put("key3", 3);
Map<Integer, Double> map2 = new HashMap<Integer, Double>();
map2.put(1, 1.0);
map2.put(2, 2.0);
map2.put(3, 3.0);
Map<String, Double> map3 = new new HashMap<String, Double>();
map1.forEach((key,value)->map3.put(key,map2.get(value)));
Cela donne la cartographie suivante
"key1" -> 1.0
"key2" -> 2.0
"key3" -> 3.0
Vérifier si la clé existe
Map<String, String> num = new HashMap<>();
num.put("one", "first");
if (num.containsKey("one")) {
System.out.println(num.get("one")); // => first
}
Les cartes peuvent contenir des valeurs nulles
Pour les cartes, il faut faire preuve de prudence pour ne pas confondre "contenant une clé" avec "avoir une valeur". Par exemple, HashMap
s peut contenir null, ce qui signifie que le comportement suivant est parfaitement normal:
Map<String, String> map = new HashMap<>();
map.put("one", null);
if (map.containsKey("one")) {
System.out.println("This prints !"); // This line is reached
}
if (map.get("one") != null) {
System.out.println("This is never reached !"); // This line is never reached
}
Plus formellement, il n'y a aucune garantie que map.contains(key) <=> map.get(key)!=null
Itérer efficacement les entrées de carte
Cette section fournit des codes et des tests d'évaluation pour dix implémentations d'exemples uniques qui parcourent les entrées d'une Map<Integer, Integer>
et génèrent la somme des valeurs Integer
. Tous les exemples ont une complexité algorithmique de Θ(n)
, cependant, les tests de performances sont toujours utiles pour fournir des informations sur les implémentations les plus efficaces dans un environnement "réel".
Iterator<Map.Entry<Integer, Integer>> it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<Integer, Integer> pair = it.next();
sum += pair.getKey() + pair.getValue();
}
for (Map.Entry<Integer, Integer> pair : map.entrySet()) {
sum += pair.getKey() + pair.getValue();
}
- Implémentation à l'aide de
Map.forEach
(Java 8+)
map.forEach((k, v) -> sum[0] += k + v);
- Implémentation à l'aide de
Map.keySet
avecfor
for (Integer key : map.keySet()) {
sum += key + map.get(key);
}
- Implémentation à l'aide de
Map.keySet
avecIterator
Iterator<Integer> it = map.keySet().iterator();
while (it.hasNext()) {
Integer key = it.next();
sum += key + map.get(key);
}
for (Iterator<Map.Entry<Integer, Integer>> entries =
map.entrySet().iterator(); entries.hasNext(); ) {
Map.Entry<Integer, Integer> entry = entries.next();
sum += entry.getKey() + entry.getValue();
}
- Implémentation à l'aide de
Stream.forEach
(Java 8+)
map.entrySet().stream().forEach(e -> sum += e.getKey() + e.getValue());
- Implémentation à l'aide de
Stream.forEach
avecStream.parallel
(Java 8+)
map.entrySet()
.stream()
.parallel()
.forEach(e -> sum += e.getKey() + e.getValue());
- Implémentation à l'aide d'
IterableMap
des collections Apache
MapIterator<Integer, Integer> mit = iterableMap.mapIterator();
while (mit.hasNext()) {
sum += mit.next() + it.getValue();
}
- Implémentation à l'aide de
MutableMap
des collections Eclipse
mutableMap.forEachKeyValue((key, value) -> {
sum += key + value;
});
Tests de performance ( code disponible sur Github )
Environnement de test: Windows 8.1 64 bits, Intel i7-4790 3,60 GHz, 16 Go
Performance moyenne de 10 essais (100 éléments) Meilleur: 308 ± 21 ns / op
Benchmark Score Error Units test3_UsingForEachAndJava8 308 ± 21 ns/op test10_UsingEclipseMutableMap 309 ± 9 ns/op test1_UsingWhileAndMapEntry 380 ± 14 ns/op test6_UsingForAndIterator 387 ± 16 ns/op test2_UsingForEachAndMapEntry 391 ± 23 ns/op test7_UsingJava8StreamAPI 510 ± 14 ns/op test9_UsingApacheIterableMap 524 ± 8 ns/op test4_UsingKeySetAndForEach 816 ± 26 ns/op test5_UsingKeySetAndIterator 863 ± 25 ns/op test8_UsingJava8StreamAPIParallel 5552 ± 185 ns/op
Performance moyenne de 10 essais (10000 éléments) Meilleur: 37.606 ± 0.790 μs / op
Benchmark Score Error Units test10_UsingEclipseMutableMap 37606 ± 790 ns/op test3_UsingForEachAndJava8 50368 ± 887 ns/op test6_UsingForAndIterator 50332 ± 507 ns/op test2_UsingForEachAndMapEntry 51406 ± 1032 ns/op test1_UsingWhileAndMapEntry 52538 ± 2431 ns/op test7_UsingJava8StreamAPI 54464 ± 712 ns/op test4_UsingKeySetAndForEach 79016 ± 25345 ns/op test5_UsingKeySetAndIterator 91105 ± 10220 ns/op test8_UsingJava8StreamAPIParallel 112511 ± 365 ns/op test9_UsingApacheIterableMap 125714 ± 1935 ns/op
Rendement moyen de 10 essais (100 000 éléments) Meilleur: 1184,767 ± 332,968 μs / op
Benchmark Score Error Units test1_UsingWhileAndMapEntry 1184.767 ± 332.968 μs/op test10_UsingEclipseMutableMap 1191.735 ± 304.273 μs/op test2_UsingForEachAndMapEntry 1205.815 ± 366.043 μs/op test6_UsingForAndIterator 1206.873 ± 367.272 μs/op test8_UsingJava8StreamAPIParallel 1485.895 ± 233.143 μs/op test5_UsingKeySetAndIterator 1540.281 ± 357.497 μs/op test4_UsingKeySetAndForEach 1593.342 ± 294.417 μs/op test3_UsingForEachAndJava8 1666.296 ± 126.443 μs/op test7_UsingJava8StreamAPI 1706.676 ± 436.867 μs/op test9_UsingApacheIterableMap 3289.866 ± 1445.564 μs/op
Une comparaison des variations de performance en fonction de la taille de la carte
x: Size of Map
f(x): Benchmark Score (μs/op)
100 600 1100 1600 2100
---------------------------------------------------
10 | 0.333 1.631 2.752 5.937 8.024
3 | 0.309 1.971 4.147 8.147 10.473
6 | 0.372 2.190 4.470 8.322 10.531
1 | 0.405 2.237 4.616 8.645 10.707
Tests 2 | 0.376 2.267 4.809 8.403 10.910
f(x) 7 | 0.473 2.448 5.668 9.790 12.125
9 | 0.565 2.830 5.952 13.22 16.965
4 | 0.808 5.012 8.813 13.939 17.407
5 | 0.81 5.104 8.533 14.064 17.422
8 | 5.173 12.499 17.351 24.671 30.403
Utiliser un objet personnalisé comme clé
Avant d'utiliser votre propre objet comme clé, vous devez remplacer la méthode hashCode () et equals () de votre objet.
Dans le cas simple, vous auriez quelque chose comme:
class MyKey {
private String name;
MyKey(String name) {
this.name = name;
}
@Override
public boolean equals(Object obj) {
if(obj instanceof MyKey) {
return this.name.equals(((MyKey)obj).name);
}
return false;
}
@Override
public int hashCode() {
return this.name.hashCode();
}
}
hashCode
décidera quel seau hachage la clé appartient et equals
à décidera quel objet dans le seau de hachage.
Sans cette méthode, la référence de votre objet sera utilisée pour la comparaison ci-dessus, ce qui ne fonctionnera que si vous utilisez la même référence d'objet à chaque fois.
Utilisation de HashMap
HashMap est une implémentation de l'interface Map qui fournit une structure de données pour stocker des données dans des paires Key-Value.
1. Déclarer HashMap
Map<KeyType, ValueType> myMap = new HashMap<KeyType, ValueType>();
KeyType et ValueType doivent être des types valides en Java, tels que - String, Integer, Float ou toute classe personnalisée comme Employee, Student, etc.
Par exemple: Map<String,Integer> myMap = new HashMap<String,Integer>();
2. Mettre des valeurs dans HashMap.
Pour mettre une valeur dans HashMap, nous devons appeler la méthode put
sur l'objet HashMap en transmettant la clé et la valeur en tant que paramètres.
myMap.put("key1", 1);
myMap.put("key2", 2);
Si vous appelez la méthode put avec la clé qui existe déjà dans la carte, la méthode remplace sa valeur et renvoie l'ancienne valeur.
3. Obtenir des valeurs de HashMap.
Pour obtenir la valeur d'un HashMap, vous devez appeler la méthode get
en transmettant la clé en tant que paramètre.
myMap.get("key1"); //return 1 (class Integer)
Si vous transmettez une clé qui n'existe pas dans HashMap, cette méthode renverra null
4. Vérifiez si la clé est dans la carte ou non.
myMap.containsKey(varKey);
5. Vérifiez si la valeur est dans la carte ou non.
myMap.containsValue(varValue);
Les méthodes ci-dessus boolean
une valeur boolean
true ou false si key, la valeur existe dans la map ou non.
Création et initialisation de cartes
introduction
Maps
stocke les paires clé / valeur, chaque clé ayant une valeur associée. Étant donné une clé particulière, la carte peut rechercher la valeur associée très rapidement.
Maps
, également appelées tableau associé, sont des objets qui stockent les données sous forme de clés et de valeurs. En Java, les cartes sont représentées à l'aide de l'interface Map, qui n'est pas une extension de l'interface de collecte.
Voie 1: -
/*J2SE < 5.0*/ Map map = new HashMap(); map.put("name", "A"); map.put("address", "Malviya-Nagar"); map.put("city", "Jaipur"); System.out.println(map);
Way 2: -
/*J2SE 5.0+ style (use of generics):*/ Map<String, Object> map = new HashMap<>(); map.put("name", "A"); map.put("address", "Malviya-Nagar"); map.put("city", "Jaipur"); System.out.println(map);
Voie 3: -
Map<String, Object> map = new HashMap<String, Object>(){{ put("name", "A"); put("address", "Malviya-Nagar"); put("city", "Jaipur"); }}; System.out.println(map);
Voie 4: -
Map<String, Object> map = new TreeMap<String, Object>(); map.put("name", "A"); map.put("address", "Malviya-Nagar"); map.put("city", "Jaipur"); System.out.println(map);
Chemin 5: -
//Java 8 final Map<String, String> map = Arrays.stream(new String[][] { { "name", "A" }, { "address", "Malviya-Nagar" }, { "city", "jaipur" }, }).collect(Collectors.toMap(m -> m[0], m -> m[1])); System.out.println(map);
Voie 6: -
//This way for initial a map in outside the function final static Map<String, String> map; static { map = new HashMap<String, String>(); map.put("a", "b"); map.put("c", "d"); }
Voie 7: - Créer une carte clé-valeur unique immuable.
//Immutable single key-value map Map<String, String> singletonMap = Collections.singletonMap("key", "value");
Veuillez noter qu'il est impossible de modifier une telle carte .
Tout objet de modification de la carte entraînera une exception UnsupportedOperationException.
//Immutable single key-value pair Map<String, String> singletonMap = Collections.singletonMap("key", "value"); singletonMap.put("newKey", "newValue"); //will throw UnsupportedOperationException singletonMap.putAll(new HashMap<>()); //will throw UnsupportedOperationException singletonMap.remove("key"); //will throw UnsupportedOperationException singletonMap.replace("key", "value", "newValue"); //will throw UnsupportedOperationException //and etc