Parcourir une Map en Java : comment itérer sans douleur et sans perte de vitesse

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Pourquoi votre code peut-il ralentir sans raison apparente ?

\n

Imaginez : vous avez écrit un algorithme parfait, passé tous les tests unitaires, mais en production l'application commence soudainement à "ralentir". Le plus souvent, ce n'est pas l'algorithme lui-même qui est en cause, mais la façon dont vous parcourez les collections. Cela concerne particulièrement la Java Map — une structure de données que l'on retrouve dans 9 projets d'entreprise sur 10.

\n

La question "How do I efficiently iterate over each entry in a Java Map?" sur Stack Overflow a recueilli des dizaines de milliers de vues pour une bonne raison. De nombreux développeurs, même avec 2-3 ans d'expérience, utilisent des approches non optimales. Voyons comment parcourir une Map correctement, et pourquoi une méthode peut être 10 fois plus rapide qu'une autre.

\n\n

Anatomie d'une Java Map : qu'y a-t-il à l'intérieur ?

\n

Avant de parler d'itération, rappelons la structure. HashMap est une table de hachage avec des buckets. TreeMap est un arbre rouge-noir. LinkedHashMap est un hybride avec une liste doublement chaînée. Chacune de ces structures stocke des paires key-value, mais les méthodes de parcours diffèrent en vitesse et en consommation mémoire.

\n

Les principales collections de vues (view collections) fournies par Map sont :

\n
    \n
  • keySet() — l'ensemble des clés
  • \n
  • values() — la collection des valeurs
  • \n
  • entrySet() — l'ensemble des paires (clé-valeur)
  • \n
\n

C'est à travers ces trois "fenêtres" que nous allons examiner les données.

\n\n

Méthode n°1 : entrySet classique avec for-each (la plus populaire)

\n

C'est un modèle de base, mais très efficace. Vous accédez à la fois à la clé et à la valeur en une seule itération.

\n
Map<String, Integer> map = new HashMap<>();\n// ... remplissage de la map\nfor (Map.Entry<String, Integer> entry : map.entrySet()) {\n    String key = entry.getKey();\n    Integer value = entry.getValue();\n    // votre logique\n}
\n

Pourquoi est-ce efficace ? Parce que entrySet() retourne une vue (view), et non une copie des données. L'itérateur parcourt les nœuds internes (Node) de HashMap, et chaque appel à next() donne immédiatement à la fois la clé et la valeur. Il n'y a pas de recherche supplémentaire par hachage.

\n

Quand l'utiliser : chaque fois que vous avez besoin des deux composants de la paire. C'est la norme de facto dans la communauté Java.

\n\n

Méthode n°2 : keySet + get (anti-patron à éviter)

\n

De nombreux débutants écrivent ceci :

\n
for (String key : map.keySet()) {\n    Integer value = map.get(key);\n    // logique\n}
\n

À première vue, le code est lisible. Mais en interne, HashMap.get() recalcule le hachage de la clé à chaque fois et parcourt la chaîne de collisions. Pour 100 éléments, c'est imperceptible, mais pour 100 000, c'est une dégradation sérieuse. Dans le pire des cas (beaucoup de collisions), la complexité passe de O(n) à O(n²).

\n

Conclusion : si vous avez besoin à la fois de la clé et de la valeur, utilisez entrySet(). Si vous n'avez besoin que des clés, keySet() est idéal.

\n\n

Méthode n°3 : Itérateur avec suppression explicite (pour les mutations pendant le parcours)

\n

Parfois, vous devez supprimer des éléments d'une Map pendant l'itération. La boucle for-each lèvera une ConcurrentModificationException. C'est là que l'itérateur vient à la rescousse :

\n
Iterator<Map.Entry<String, Integer>> iterator = map.entrySet().iterator();\nwhile (iterator.hasNext()) {\n    Map.Entry<String, Integer> entry = iterator.next();\n    if (entry.getValue() < 0) {\n        iterator.remove(); // suppression sécurisée\n    }\n}
\n

Cette méthode est particulièrement utile lorsque vous filtrez des données "à la volée". L'itérateur fonctionne en O(1) pour chaque suppression dans HashMap, car il connaît le nœud actuel.

\n\n

Méthode n°4 : forEach avec lambda (Java 8+)

\n

Depuis Java 8, Map a sa propre méthode forEach :

\n
map.forEach((key, value) -> {\n    System.out.println(key + " -> " + value);\n});
\n

Sous le capot

Blogs

Book Recommendations