Collection 04 : Map
Que ce soit avec des listes ou des ensembles, tu as pu rassembler des éléments, triés ou non. Dans le cas des listes, un index numérique est attribué automatiquement.
Mais que faire si tu désires attribuer toi-même un index aux éléments ? Et si cet index ne doit pas être pas numérique ?
Par exemple, un index pourrait être un pays, sa valeur associée étant sa capitale : pour réaliser cela, tu vas avoir besoin des tableaux associatifs (ou dictionnaires). En Java, cela est représenté par l'interface Map !
Objectifs
- Savoir initialiser et utiliser un tableau associatif
- Trier un tableau associatif par ordre d'insertion des clés
- Trier un tableau associatif par valeur des clés
Map
Si nous reprenons l'exemple de l'introduction, un tableau associatif de pays avec leurs capitales respectives ressemble à cela :
{
"Allemagne": "Berlin",
"Autriche": "Vienne",
"Belgique": "Bruxelles",
"Bulgarie": "Sofia",
"Chypre": "Nicosie",
"Croatie": "Zagreb",
"Danemark": "Copenhague",
"Espagne": "Madrid",
// ...
}
L'interface Map<K,V> est représentée par les types de la clé K et le type de la valeur V : dans l'exemple, il s'agit de Map<String, String>.
Un
Mappeut avoir n'importe quel type objet en clé, de même qu'en valeur. Il peut même y avoir une liste, un ensemble, voire même un autre tableau associatif !
Un tableau associatif est composé de trois zones distinctes :
-
l'ensemble de ses clés,
keySet: deux clés ne peuvent être identiques -
la collection de ses valeurs,
values: il est possible d'avoir des valeurs identiques -
l'ensemble des couples clé-valeur,
entrySet: pas de doublons possibles
Il existe plusieurs implémentations de l'interface Map, notamment :
-
sans ordre défini, avec
HashMap -
par ordre d'insertion, avec
LinkedHashMap -
par ordre de valeur des clés, avec
TreeMap
Au contraire de List et Set, l'interface Map n'hérite pas de Collection.

_Credit _Alla Gorik
HashMap
Si l'ordre des clés importe peu, il est conseillé d'utiliser l'implémentation HashMap.
Pour créer un nouvel HashMap vide, tu vas devoir créer une instance de la classe et la stocker dans une référence :
Map<User, Computer> classroom = new HashMap<>();
Ici, nous avons la représentation d'une salle de classe, avec pour chaque utilisateur User un ordinateur associé Computer.
Les clés étant un ensemble, il n'est pas possible d'y avoir plusieurs fois le même utilisateur avec des ordinateurs différents. Cependant, il est envisageable que deux utilisateurs aient le même ordinateur (travail en peer-programming !).
Avant de voir quelques méthodes, commençons par initialiser des instances que nous utiliserons par la suite :
User bernard = new User("Bernard");
User laverne = new User("Laverne");
User hoagie = new User("Hoagie");
User surfer = new User("Jeff Woodie");
Computer sx386 = new Computer("386SX-25");
Computer dx486 = new Computer("486DX2-66");
Computer c64 = new Computer("Commodore 64");
1. Insertion
L'insertion d'un couple clé-valeur se fait grâce à la méthode put(K key, V value) :
Map<User, Computer> classroom = new HashMap<>();
classroom.put(bernard, dx486);
classroom.put(laverne, sx386);
classroom.put(hoagie, sx386);
classroom.put(surfer, c64);
Comme tu peux le remarquer, il est possible d'assigner la même valeur à des clés différentes.
2. Suppression
Tu peux supprimer un élément grâce à sa clé. L'élément supprimé sera renvoyé :
Computer removed = classroom.remove(surfer);
System.out.println(removed.getModel()); // Commodore 64
3. Ensemble des clés
Il est possible de récupérer l'ensemble des clés (Set) du tableau associatif avec la méthode keySet() :
for (User user : classroom.keySet()) {
System.out.println(user.getName());
}
$ Bernard
$ Hoagie
$ Laverne
Comme les clés sont dans un ensemble, l'ordre n'est pas garanti
4. Collection des valeurs
Il est possible de récupérer la collection des valeurs (Collection) du tableau associatif avec la méthode values() :
for (Computer computer : classroom.values()) {
System.out.println(computer.getModel());
}
$ 486DX2-66
$ 386SX-25
$ 386SX-25
Les valeurs sont classées par ordre d'insertion
5. Parcourir l'ensemble des couples clé-valeur
Il est possible de récupérer l'ensemble des couples clé-valeur (Set) du tableau associatif avec la méthode entrySet(). Le type du couple clé-valeur sera Map.Entry<K, V>, de clé K et de valeur V.
Il est possible de parcourir cet ensemble et, pour chaque couple, d'en récupérer la clé avec la méthode getKey(), ainsi que la valeur avec la méthode getValue() :
for (Map.Entry<User, Computer> entry : classroom.entrySet()) {
User user = entry.getKey();
Computer computer = entry.getValue();
System.out.println(user.getName() + ": " + computer.getModel());
}
$ Bernard: 486DX2-66
$ Hoagie: 386SX-25
$ Laverne: 386SX-25
Comme les couples clé-valeur sont dans un ensemble, l'ordre n'est pas garanti
6. Rechercher une clé et une valeur
Il est possible de chercher si un tableau associatif contient une clé ou une valeur, grâce aux méthodes containsKey(Object o) et containsValue(Object o) :
System.out.println(classroom.containsKey(bernard)); // true
System.out.println(classroom.containsValue(c64)); // false
LinkedHashMap
Si tu désires avoir un tableau associatif classé par ordre d'insertion des éléments, c'est du côté de LinkedHashMap que tu vas devoir regarder !
Ainsi, le parcours des éléments se fera dans l'ordre dans lequel ils ont été ajoutés :
Map<User, Computer> linkedClassroom = new LinkedHashMap<>();
linkedClassroom.put(bernard, dx486);
linkedClassroom.put(laverne, sx386);
linkedClassroom.put(hoagie, sx386);
linkedClassroom.put(surfer, c64);
for (User user : linkedClassroom.keySet()) {
Computer computer = linkedClassroom.get(user);
System.out.println(user.getName() + ": " + computer.getModel());
}
$ Bernard: 486DX2-66
$ Laverne: 386SX-25
$ Hoagie: 386SX-25
$ Jeff Woodie: Commodore 64
TreeMap
Un tableau associatif TreeMap permet, quant à lui, de trier les éléments par valeur des clés.
Map<User, Computer> treeClassroom = new TreeMap<>();
Mais avec le code tel quel, tu auras l'erreur suivante à la compilation :
class User cannot be cast to class java.lang.Comparable
Il faut donc attribuer aux clés un ordre par défaut :
-
soit en implémentant
Comparablepréalablement -
soit au moment de la création du tableau associatif, en instanciant une classe anonyme de
Comparator
Ci-dessous, tu peux observer comment créer une instance de TreeMap avec un Comparator :
Comparator<User> comparator = new Comparator<User>() {
@Override
public int compare(User orig, User compare) {
return orig.getName().compareTo(compare.getName());
}
};
Map<User, Computer> treeClassroom = new TreeMap<>(comparator);
treeClassroom.put(bernard, dx486);
treeClassroom.put(laverne, sx386);
treeClassroom.put(hoagie, sx386);
treeClassroom.put(surfer, c64);
Ainsi, le parcours des éléments se fera dans l'ordre alphabétique des clés :
for (User user : treeClassroom.keySet()) {
Computer computer = treeClassroom.get(user);
System.out.println(user.getName() + ": " + computer.getModel());
}
$ Bernard: 486DX2-66
$ Hoagie: 386SX-25
$ Jeff Woodie: Commodore 64
$ Laverne: 386SX-25
Bien choisir sa collection
Afin de voir en situation toutes les notions abordées par la quête, récupère le dépôt git donné en ressource.
Après toutes ces quêtes sur les collections, tu dois commencer à te demander lesquelles choisir et dans quels cas !

_Credit _Yash-777
Voici un super diagramme (à garder sous la main) qui va t'aider dans ces lourdes décisions !

_Credit _Ramesh Fadatare
Challenge
Avengers : Pre-Sequel Part.2
Thanos est finalement devenu fan des Avengers et a décidé, après les avoir plus ou moins ressuscités, d'utiliser son Gant de l'infini afin d'organiser une fête.
Afin d'épater la galerie, il veut offrir à chaque invité sa fleur préférée !
Pour démarrer, fais un Fork du dépôt suivant puis clone-le en local.
Pense bien à faire un Fork, sinon tu ne pourras rien pousser !
Thanos possède des éléments Hero et Flower :
-
Construire un
TreeMapnomméparty, avec en cléHeroet valeurFlower -
Ajouter dans
partyles couples clé/valeur suivants :
* *Hulk*, *Thor* et *Scarlet Witch* ont une *Rose *
* *Vision* a une *Tulip *
* *Captain America* a une *Lily*
* *Doctor Strange* et *Black Widow* ont une *Violet*
-
En une seule ligne, afficher si
partycontient l'instancebegonia -
Parcourir le tableau associatif par ordre alphabétique de nom de héros, et afficher, pour chacun d'entre eux, sa fleur attribuée.
Résultat attendu lors de l'exécution de Thanos :
$ false
$ Violet
$ Lily
$ Violet
$ Rose
$ Rose
$ Rose
$ Tulip
Critères de validation
- Le dépôt GitHub contient bien les fichiers
Hero.javaetThanos.java - La classe
Thanosdoit être modifiée - La classe
Heropeut être modifiée (mais ce n'est pas obligatoire) - La classe
Thanosse compile sans erreur et affiche dans le terminal un résultat identique à celui présenté précédemment