129 votes

Suppression des éléments d'un HashSet pendant l'itération

Ainsi, si j'essaie de supprimer des éléments d'un fichier Java HashSet en itérant, j'obtiens un ConcurrentModificationException . Quelle est la meilleure façon de supprimer un sous-ensemble d'éléments d'un fichier HashSet comme dans l'exemple suivant ?

Set<Integer> set = new HashSet<Integer>();

for(int i = 0; i < 10; i++)
    set.add(i);

// Throws ConcurrentModificationException
for(Integer element : set)
    if(element % 2 == 0)
        set.remove(element);

Voici une solution, mais je ne pense pas qu'elle soit très élégante :

Set<Integer> set = new HashSet<Integer>();
Collection<Integer> removeCandidates = new LinkedList<Integer>();

for(int i = 0; i < 10; i++)
    set.add(i);

for(Integer element : set)
    if(element % 2 == 0)
        removeCandidates.add(element);

set.removeAll(removeCandidates);

Merci !

196voto

Adam Paynter Points 22056

Vous pouvez itérer manuellement sur les éléments de l'ensemble :

Iterator<Integer> iterator = set.iterator();
while (iterator.hasNext()) {
    Integer element = iterator.next();
    if (element % 2 == 0) {
        iterator.remove();
    }
}

Vous verrez souvent ce modèle en utilisant un for plutôt qu'une boucle while boucle :

for (Iterator<Integer> i = set.iterator(); i.hasNext();) {
    Integer element = i.next();
    if (element % 2 == 0) {
        i.remove();
    }
}

Comme les gens l'ont souligné, l'utilisation d'un for est préférée car elle conserve la variable de l'itérateur ( i dans ce cas) confiné à un champ d'application plus restreint.

27voto

sjlee Points 3457

La raison pour laquelle vous obtenez un ConcurrentModificationException c'est parce qu'une entrée est supprimée via Set.remove() à l'opposé de Iterator.remove() . Si une entrée est supprimée via Set.remove() pendant qu'une itération est en cours, vous obtiendrez une ConcurrentModificationException. D'autre part, la suppression d'entrées via Iterator.remove() alors que l'itération est supportée dans ce cas.

La nouvelle boucle for est intéressante, mais malheureusement elle ne fonctionne pas dans ce cas, car vous ne pouvez pas utiliser la référence Iterator.

Si vous devez supprimer une entrée pendant l'itération, vous devez utiliser la forme longue qui utilise directement l'Iterator.

for (Iterator<Integer> it = set.iterator(); it.hasNext();) {
    Integer element = it.next();
    if (element % 2 == 0) {
        it.remove();
    }
}

16voto

risoldi Points 409

Java 8 Collection possède une méthode intéressante appelée removeIf qui rend les choses plus faciles et plus sûres. Extrait de la documentation de l'API :

default boolean removeIf(Predicate<? super E> filter)
Removes all of the elements of this collection that satisfy the given predicate. 
Errors or runtime exceptions thrown during iteration or by the predicate 
are relayed to the caller.

Note intéressante :

The default implementation traverses all elements of the collection using its iterator(). 
Each matching element is removed using Iterator.remove().

De : https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html#removeIf-java.util.function.Predicate-

10voto

dfa Points 54490

Vous pouvez également remanier votre solution en supprimant la première boucle :

Set<Integer> set = new HashSet<Integer>();
Collection<Integer> removeCandidates = new LinkedList<Integer>(set);

for(Integer element : set)
   if(element % 2 == 0)
       removeCandidates.add(element);

set.removeAll(removeCandidates);

10voto

Getriax Points 143

Comme Timber l'a dit - "Java 8 Collection a une méthode agréable appelée removeIf qui rend les choses plus faciles et plus sûres".

Voici le code qui résout votre problème :

set.removeIf((Integer element) -> {
    return (element % 2 == 0);
});

Maintenant, votre ensemble ne contient que des valeurs impaires.

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