3 votes

Pourquoi est-ce que j'obtiens une ConcurentModificationException lorsque je supprime un élément d'un HashMap ?

Je veux supprimer un élément de HashMap, en appliquant un critère. Considérez ce code :

Set<Foo> set = myMap.keySet();
Iterator<Foo> itr = set.iterator();
while (itr.hasNext())
{
    Foo foo = itr.next();
    if (foo.toString().length() < 3) {
        myMap.remove(foo); //remove the pair if key length is less than 3
    }
}

J'obtiens donc une ConcurentModificationException car, pendant l'itération, je modifie le HashMap. Que dois-je faire ? Existe-t-il un autre moyen de rechercher mes critères et d'exécuter la commande remove à la fin afin d'éviter cette exception ?

13voto

a_horse_with_no_name Points 100769

Utilice itr.remove() au lieu de myMap.remove(o.toString())

4voto

Jeffrey Bosboom Points 1255

À partir de Java 8, Collection fournit removeIf(Predicate<? super E>) qui supprimera tous les éléments pour lesquels le prédicat donné retourne vrai. L'exemple de la question pourrait être réécrit comme suit

myMap.keySet().removeIf(o -> o.toString().length() < 3);

L'implémentation par défaut fournie par Collection utilise un itérateur et appelle Iterator.remove mais les collections peuvent passer outre s'ils peuvent fournir de meilleures implémentations. Plus important encore, le code utilisant removeIf est plus claire et plus concise.

3voto

AlexR Points 60796

Si vous supprimez un élément pendant l'itération, vous devez utiliser Iterator.remove() à la place. Sinon, l'objet Iterator actuel entre dans un état incohérent qui provoque l'exception. Vous pouvez utiliser Map.remove(key) lorsque vous connaissez la clé, c'est-à-dire lorsque vous n'itérez pas sur la même Map.

Cette règle est correcte pour toutes les collections (Listes, Sets etc.).

1voto

Bozho Points 273663

Oui - itr.remove()

Supprime de la collection sous-jacente le dernier élément renvoyé par l'itérateur (opération facultative). Cette méthode ne peut être appelée qu'une seule fois par appel à next.

En Iterator de la keySet() prolonge le HashIterator dont remove() appels de méthodes HashMap.this.removeEntryForKey(key);

Vous pouvez également obtenir le entrySet() si vous avez besoin à la fois de la clé et de la valeur - son itérateur a la même propriété.

0voto

ytoh Points 89

Pour faire ce que vous décrivez, j'aime personnellement utiliser la programmation de style fonctionnel :

Map<String,Object> map = // obtained somehow;

Map<String,Object> filtered = Maps.filterKeys(map, new Predicate() {
    @Override
    public boolean apply(String input) {
        return input.length() < 3;
    }
});

L'extrait de code utilise la bibliothèque google collections. Il crée une vue de la carte originale en prenant uniquement les entrées dont les clés correspondent au prédicat fourni.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X