Java Reskilling Data-Structures 02: Map
Les structures de données Java : Map
Dans les quêtes sur les structures de données Java de base, tu vas apprendre à partir d'exemples tirés de notre application de démonstration Tariff-Manager.
Dans cette quête, une structure de données Java fondamentale, la
Map(table de correspondance clé-valeur), sert à associer des clés à des valeurs (c'est-à-dire des paires clé-valeur) dans notre application Tariff-Manager. Il existe différentes implémentations de laMap, que nous allons explorer dans le contexte du domaine Tariff-Manager.

🤓 À la fin de cette quête, tu sauras :
✅Créer une Map pour stocker des paires clé-valeur.
✅Utiliser une Map pour travailler sur les valeurs stockées.
✅Comprendre la différence entre les façons d'utiliser une Map pour travailler sur les valeurs stockées.
👀 Contenu de la quête
- Interface :
Map - Implémentation :
HashMap - Implémentation :
LinkedHashMap - Implémentation :
TreeMap - Comment choisir ta collection Java
👉Interface : Map
Que ce soit avec les listes ou les ensembles (set, collection sans doublons), tu as pu regrouper des éléments, triés ou non. Dans le cas des listes, un index numérique est attribué automatiquement.
Mais que se passe-t-il si tu veux attribuer toi-même un index aux éléments ? Et si cet index n'a pas besoin d'être numérique ?
Par exemple, un index pourrait être un pays, la valeur associée étant sa capitale : pour cela, tu auras besoin des tableaux associatifs (ou dictionnaires). En Java, c'est représenté par l'interface Map !
Un tableau associatif de pays avec leurs capitales respectives ressemble à ceci :
{
"Austria": "Vienna",
"Belgium": "Brussels",
"Bulgaria": "Sofia",
"Croatia": "Zagreb",
"Denmark": "Copenhague",
"Spain": "Madrid",
// ...
}
Dans un environnement d'entreprise, on manipule souvent des structures synthétiques comme des correspondances ID-Client, par exemple :
{
"AJ55Y26": "Average Joe",
"CC55X16": "Chatty Cathy",
"DD55Z88": "Debbie Downer",
"DT66B87": "Doubting Thomas",
"GG99N88": "Gloomy Gus",
"GC11O66": "Good-Time Charlie",
// ...
}
L'interface Map<K,V> est représentée par le type de clé K et le type de valeur V ; dans l'exemple, il s'agit de Map<String, String>.
Une
Mappeut avoir n'importe quel type d'objet comme clé, ainsi que comme valeur. Ça peut même être une liste, un ensemble, ou encore un autre tableau associatif !
Un tableau associatif se compose de trois zones distinctes :
keySet: l'ensemble de ses clés, deux clés ne peuvent pas être identiquesvalues: la collection de ses valeurs, il est possible d'avoir des valeurs identiquesentrySet: l'ensemble des paires clé-valeur, aucun doublon possible
Il existe plusieurs implémentations de l'interface Map, notamment :
- sans ordre défini, avec
HashMap - dans l'ordre d'insertion, avec
LinkedHashMap - triée selon la valeur des clés, avec
TreeMap
Contrairement aux interfaces List et Set, la Map n'hérite pas de Collection.
Crédit Alla Gorik
👉Implémentation : HashMap
Si l'ordre des clés n'a pas d'importance, il est conseillé d'utiliser l'implémentation HashMap.
Pour créer une nouvelle HashMap vide, tu devras créer une instance de la classe et la stocker dans une référence :
Map<Employee, Department> company = new HashMap<>();
Ici, on a la représentation d'une entreprise, avec pour chaque Employee un département associé dans l'entreprise Department.
Les clés formant un ensemble, il n'est pas possible d'avoir le même employé plusieurs fois dans différents départements. En revanche, les départements ont très probablement plusieurs employés, donc les valeurs peuvent être des doublons.
Avant de regarder quelques méthodes, commençons par initialiser quelques instances que nous utiliserons plus tard :
Employee bernard = new Employee("Bernard");
Employee laverne = new Employee("Laverne");
Employee hoagie = new Employee("Hoagie");
Employee surfer = new Employee("Jeff Woodie");
Department sales = new Department("Sales");
Department hr = new Department("HR");
Department it = new Department("IT");
Insertion
L'insertion d'une paire clé-valeur se fait avec la méthode put(K key, V value) :
Map<Employee, Department> company = new HashMap<>();
company.put(bernard, sales);
company.put(laverne, sales);
company.put(hoagie, hr);
company.put(surfer, it);
Comme tu peux le voir, il est possible d'attribuer la même valeur à différentes clés.
Suppression
Tu peux supprimer un élément grâce à sa clé. L'élément supprimé sera retourné :
Employee removed = company.remove(surfer);
System.out.println(removed.getName()); // Jeff Woodie
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 (Employee employee : company.keySet()) {
System.out.println(employee.getName());
}
$ Bernard
$ Hoagie
$ Laverne
Comme les clés sont dans un ensemble, l'ordre n'est pas garanti.
Collection de valeurs
Il est possible de récupérer la collection de valeurs (Collection) du tableau associatif avec values() :
for (Department department : company.values()) {
System.out.println(department.getName());
}
$ Sales
$ Sales
$ HR
$ IT
Remarque : les valeurs sont triées dans l'ordre d'insertion.
Parcourir l'ensemble des paires clé-valeur
Il est possible de récupérer toutes les paires clé-valeur (Set) du tableau associatif avec entrySet(). Le type de la paire clé-valeur sera Map.Entry<K, V>, avec la clé K et la valeur V.
Il est possible de parcourir cet ensemble et, pour chaque paire, de récupérer la clé avec la méthode getKey() et la valeur avec getValue() :
for (Map.Entry<Employee, Department> entry : company.entrySet()) {
Employee employee = entry.getKey();
Department department = entry.getValue();
System.out.println(company.getName() + " works in " + department.getName());
}
$ Bernard works in Sales
$ Hoagie works in Sales
$ Laverne works in HR
$ Jeff works in IT
Comme les paires clé-valeur sont dans un ensemble, l'ordre n'est pas garanti.
Rechercher une clé et une valeur
Il est possible de savoir 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(company.containsKey(bernard)); // true
System.out.println(company.containsValue(orga)); // false
👉Implémentation : LinkedHashMap
Si tu veux un tableau associatif trié selon l'ordre dans lequel les éléments sont insérés, c'est du côté de LinkedHashMap qu'il va falloir regarder !
Ainsi, les éléments seront parcourus dans l'ordre où ils ont été ajoutés :
Map<Employee, Department> linkedCompany = new LinkedHashMap<>();
linkedCompany.put(bernard, sales);
linkedCompany.put(laverne, sales);
linkedCompany.put(hoagie, hr);
linkedCompany.put(surfer, it);
for (Employee employee : linkedCompany.keySet()) {
Department department = linkedCompany.get(employee);
System.out.println(employee.getName() + " works in " + department.getName());
}
$ Bernard works in Sales
$ Laverne works in Sales
$ Hoagie works in HR
$ Jeff Woodie works in IT
👉Implémentation : TreeMap
Un tableau associatif TreeMap te permet de trier les éléments selon la valeur des clés.
Map<Employee, Department> treeCompany = new TreeMap<>();
Mais avec le code tel quel, tu obtiendras l'erreur suivante à la compilation :
class Employee cannot be cast to class java.lang.Comparable
Les clés doivent donc se voir attribuer un ordre par défaut :
- soit en implémentant
Comparableau préalable - soit au moment de la création du tableau associatif, en instanciant une classe anonyme à partir de
Comparator
Ci-dessous, tu peux voir comment créer une instance de TreeMap avec un Comparator :
Comparator<Employee> comparator = new Comparator<>() {
@Override
public int compare(Employee orig, Employee compare) {
return orig.getName().compareTo(compare.getName());
}
};
Map<Employee, Department> treeCompany = new TreeMap<>(comparator);
treeCompany.put(bernard, sales);
treeCompany.put(laverne, sales);
treeCompany.put(hoagie, hr);
treeCompany.put(surfer, it);
Ainsi, les éléments seront parcourus dans l'ordre alphabétique des clés :
for (Employee employee : treeCompany.keySet()) {
Department department = treeCompany.get(employee);
System.out.println(employee.getName() + " works in " + department.getName());
}
$ Bernard: Sales
$ Hoagie: HR
$ Jeff Woodie: IT
$ Laverne: Sales
👉Comment choisir ton implémentation de Collection ou de Map
Pour voir en situation toutes les notions abordées dans la quête, récupère le dépôt git fourni en ressource.
Après toutes ces quêtes sur les collections, tu dois commencer à te demander lesquelles choisir et quand !
Crédit Yash-777
Voici un super schéma (à garder sous la main) qui t'aidera dans ces décisions difficiles !
Crédit Ramesh Fadatare
🔬Exercice
On peut stocker n'importe quel objet comme clé ou comme valeur, et pourquoi pas une List ? En réalité, on peut aussi stocker une liste de valeurs comme valeur dans une Map. Un exemple pour nos Maps serait une association de Department vers Employee. Alors qu'un employé ne peut travailler que dans un seul département, un département peut employer de nombreux employés.
Tu dois créer deux départements : HR et IT. Ces départements sont simplement des Strings dans une structure de données Map<String, List<String>>. Les valeurs sont des Lists de Strings, qui représentent les employés.
Tu dois implémenter cette association :
HR: "Joe, Jack, April"
IT: "Roy, Maurice, Jen"
Étapes
- Crée d'abord les listes
List<String>avec les différents employés - Crée une nouvelle
Map<String, List<String>> - Place l'association clé, valeur dans la
Map
Reveal the Map and List implementations|||java||||||1|||
// Create lists of employees (as strings)
List<String> hr = List.of("Joe", "Jack", "April");
List<String> it = List.of("Roy", "Maurice", "Jen");
// Create Map to associate departement (as string) to employees
Map<String, List<String>> departments = new HashMap<>();
departments.put("HR", hr);
departments.put("IT", it);
☝️Résumé
Dans cette quête, tu as appris à stocker des informations non seulement dans une liste séquentielle, mais aussi sous forme de paires clé-valeur, ce qui te permet de récupérer une valeur directement en fournissant sa clé. Tu as vu comment associer des valeurs comme des capitales à des clés comme des pays, ou des employés comme clés à des départements comme valeurs.
Nous avons utilisé toutes sortes d'implémentations de Map pour réaliser ça en Java, certaines triées, d'autres non.
Comme avec les Collections, tu as appris à
- Créer une nouvelle
Map - Itérer sur une
Map, ses clés et ses valeurs - Stocker des éléments dans une
Map - Récupérer des éléments ou des entrées (paires clé-valeur) depuis une
Map
Pour refaire ces tâches, clone l'application de démonstration Tariff-Manager, bascule sur la branche block_2_complete et jette un œil à dev.wcs.nad.tariffmanager.customer.CustomerCollectionTest ainsi qu'au test unitaire shouldDemonstrateJavaMaps.
Challenge
C'est un challenge de type Quizz.
Références
- Photo de Max Langelott sur Unsplash
Java Data-Structures: Map
In the quests about basic Java Data-Structures you will learn with examples from the domain of our sample application Tariff-Manager.
In this quest a fundamental Java Data-Structure (
Map) is used for mapping keys to values (ie. keys-value-pairs) in our Tariff-Manager application. There are different implementations ofMap, which we will investigate in the context of the Tariff-Manager domain.

🤓 By the end of this quest, you will:
✅Know how to create a Map to store key-value pairs.
✅Know how to use a Map to work on stored values.
✅Understand the difference between How to use a Map to work on stored values.
👀 Content of the quest
- Interface:
Map - Implementation:
HashMap - Implementation:
LinkedHashMap - Implementation:
TreeMap - How to choose your Java collection
👉Interface: Map
Whether with lists or sets, you were able to gather elements, sorted or not. In the case of lists, a numerical index is assigned automatically.
But what if you want to assign an index to the elements yourself? What if this index does not have to be numerical?
For example, an index could be a country, its associated value being its capital: to do this, you will need the associative arrays (or dictionaries). In Java, this is represented by the Map interface!
An associative table of countries with their respective capitals looks like this:
{
"Austria": "Vienna",
"Belgium": "Brussels",
"Bulgaria": "Sofia",
"Croatia": "Zagreb",
"Denmark": "Copenhague",
"Spain": "Madrid",
// ...
}
In an enterprise environment, we often deal with synthetic structures like ID-Customer mappings, eg:
{
"AJ55Y26": "Average Joe",
"CC55X16": "Chatty Cathy",
"DD55Z88": "Debbie Downer",
"DT66B87": "Doubting Thomas",
"GG99N88": "Gloomy Gus",
"GC11O66": "Good-Time Charlie",
// ...
}
The interface Map<K,V> is represented by the key types K and the type of value V in the example, it is about Map<String, String>.
A
Mapcan have any object type as a key, as well as a value. There can even be a list, a set, or even another associative array!
An associative array is composed of three distinct areas:
keySet: all of his keys, two keys cannot be identicalvalues: the collection of its values, it is possible to have identical valuesentrySet: the set of key-value pairs, no duplicates possible
There are several implementations of the interface Map, including:
- without a defined sequence, with
HashMap - in order of insertion, with
LinkedHashMap - sorted by the value of the keys, with
TreeMap
In contrast to List and Set interface, the Map does not inherit Collection.
Credit Alla Gorik
👉Implementation: HashMap
If the order of the keys does not matter, it is advisable to use the implementation HashMap.
To create a new HashMap empty, you'll have to create an instance of the class and store it in a reference:
Map<Employee, Department> company = new HashMap<>();
Here we have the representation of a company, with for each Employee an associated department in the company Department.
The keys being a set, it is not possible to have the same employee several times in different departments. However, departments most likely have multiple employees, therefore the values can be duplicates.
Before looking at some methods, let's start by initializing some instances that we will use later:
Employee bernard = new Employee("Bernard");
Employee laverne = new Employee("Laverne");
Employee hoagie = new Employee("Hoagie");
Employee surfer = new Employee("Jeff Woodie");
Department sales = new Department("Sales");
Department hr = new Department("HR");
Department it = new Department("IT");
Insertion
The insertion of a key-value couple is done by the method put(K key, V value):
Map<Employee, Department> company = new HashMap<>();
company.put(bernard, sales);
company.put(laverne, sales);
company.put(hoagie, hr);
company.put(surfer, it);
As you can see, it is possible to assign the same value to different keys.
Deletion
You can delete an item with its key. The deleted item will be returned:
Employee removed = company.remove(surfer);
System.out.println(removed.getName()); // Jeff Woodie
Set of keys
It is possible to retrieve the set of keys (Set) of the associative array with the keySet() method:
for (Employee employee : company.keySet()) {
System.out.println(employee.getName());
}
$ Bernard
$ Hoagie
$ Laverne
As the keys are in a set, order is not guaranteed.
Collection of values
It is possible to retrieve the collection of values (Collection) of the associative array with values():
for (Department department : company.values()) {
System.out.println(department.getName());
}
$ Sales
$ Sales
$ HR
$ IT
Note: The values are sorted in order of insertion.
Browse through the set of key-value pairs
It is possible to retrieve all key-value pairs (Set) of the associative array with the entrySet(). The type of the key-value pair will be Map.Entry<K, V>, key K and valuable V.
It is possible to browse through this set and, for each couple, to retrieve the key with the method getKey() and the value with the getValue():
for (Map.Entry<Employee, Department> entry : company.entrySet()) {
Employee employee = entry.getKey();
Department department = entry.getValue();
System.out.println(company.getName() + " works in " + department.getName());
}
$ Bernard works in Sales
$ Hoagie works in Sales
$ Laverne works in HR
$ Jeff works in IT
As the key-value pairs are in a set, the order is not guaranteed.
Search for a key and a value
It is possible to find out whether an associative array contains a key or a value, using the methods containsKey(Object o) and containsValue(Object o):
System.out.println(company.containsKey(bernard)); // true
System.out.println(company.containsValue(orga)); // false
👉Implementation: LinkedHashMap
If you want to have an associative array sorted by the order in which the elements are inserted, it is on the side of LinkedHashMap that you're gonna have to watch!
Thus, the elements will be browsed in the order in which they were added:
Map<Employee, Department> linkedCompany = new LinkedHashMap<>();
linkedCompany.put(bernard, sales);
linkedCompany.put(laverne, sales);
linkedCompany.put(hoagie, hr);
linkedCompany.put(surfer, it);
for (Employee employee : linkedCompany.keySet()) {
Department department = linkedCompany.get(employee);
System.out.println(employee.getName() + " works in " + department.getName());
}
$ Bernard works in Sales
$ Laverne works in Sales
$ Hoagie works in HR
$ Jeff Woodie works in IT
👉Implementation: TreeMap
An associative array TreeMap allows you to sort the elements by key value.
Map<Employee, Department> treeCompany = new TreeMap<>();
But with the code as is, you'll get the following error at compile time:
class Employee cannot be cast to class java.lang.Comparable
The keys must therefore be assigned a default order:
- either by implementing
Comparablebeforehand - either at the time of the creation of the associative array, by instantiating an anonymous class from
Comparator
Below, you can see how to create an instance of TreeMap with a Comparator:
Comparator<Employee> comparator = new Comparator<>() {
@Override
public int compare(Employee orig, Employee compare) {
return orig.getName().compareTo(compare.getName());
}
};
Map<Employee, Department> treeCompany = new TreeMap<>(comparator);
treeCompany.put(bernard, sales);
treeCompany.put(laverne, sales);
treeCompany.put(hoagie, hr);
treeCompany.put(surfer, it);
So, elements will be browsed in alphabetical order of the keys:
for (Employee employee : treeCompany.keySet()) {
Department department = treeCompany.get(employee);
System.out.println(employee.getName() + " works in " + department.getName());
}
$ Bernard: Sales
$ Hoagie: HR
$ Jeff Woodie: IT
$ Laverne: Sales
👉How to choose your Collection or Map implementation
In order to see in situation all the notions approached by the quest, retrieve the git repository given as a resource.
After all those collection quests, you have to start asking yourself which ones to choose and when!
Credit Yash-777
Here's a great diagram (to keep on hand) that will help you with those tough decisions!
Credit Ramesh Fadatare
🔬Exercise
We can store any object as key or as value, how about a List? Actually we can store a list of values as a value in a Map as well. An example for our Maps would be an association of Department to Employee. While an employee can only work in one department, a department can employ many employees.
You should create two departments: HR and IT. These departments are just Strings in a Map<String, List<String>> datastructure. The values are Lists of Strings, which represent the employees.
You should implement this association:
HR: "Joe, Jack, April"
IT: "Roy, Maurice, Jen"
Steps
- First create the
List<String>lists with the different employees - Create a new
Map<String, List<String>> - Put the association as key, value into the
Map
Reveal the Map and List implementations|||java||||||1|||
// Create lists of employees (as strings)
List<String> hr = List.of("Joe", "Jack", "April");
List<String> it = List.of("Roy", "Maurice", "Jen");
// Create Map to associate departement (as string) to employees
Map<String, List<String>> departments = new HashMap<>();
departments.put("HR", hr);
departments.put("IT", it);
☝️Summary
In this Quest, you learned how to store information not only in a sequential list, but in key-value pairs, which allows you to retrieve a value directly by providing its key. You saw how to associate values like capitals with keys like countries or employees as keys to departments as values.
We used all kind of Map implementations to realize this in Java, some sorted, some not.
Like with Collections, you learned how to
- Create a new
Map - Iterator over a
Map, their keys and values - Store elements into a
Map - Retrieve elements or entries (key-value pairs) from a
Map
To reiterate these tasks, clone the sample application Tariff-Manager, switch to the branch block_2_complete and take a look at dev.wcs.nad.tariffmanager.customer.CustomerCollectionTest and the unit test shouldDemonstrateJavaMaps.
Challenge
This is a Quizz challenge.
References
- Photo by Max Langelott on Unsplash