2
votes

Comment supprimer des éléments d'un HashMap sans obtenir ConcurrentModificationException

Je compare toutes les entrées d'un HashMap à toutes les autres entrées du même HashMap . Lors de l'itération du HashMap , je supprime certains éléments en fonction de certaines conditions. Cependant, je continue à recevoir l 'ConcurrentModificationException.

    Iterator<Entry<String, String>> i = map.entrySet().iterator();

    while (i.hasNext()) {
        Entry<String, String> next = i.next();

        for (Entry<String,String> e : map.entrySet()) {

            if (e.getKey() != next.getKey()){                 
              String[] positions_e = fields_e[1].split("-");
              int start_e = Integer.parseInt(positions_e[0]);
              int end_e =  Integer.parseInt(positions_e[1]);

              String[] positions_next = fields_next[1].split("-");
              int start_next = Integer.parseInt(positions_next[0]);
              int end_next =  Integer.parseInt(positions_next[1]);

            if (start_e <= start_next || end_e <= end_next )) { 
                 i.remove();        
           } 

       }

   }


12 commentaires

Créez une nouvelle collection de clés à supprimer et au lieu de i.remove (); faites toBeRemoved.add (i.getKey ()); . Puis en dehors de la boucle while toBeRemoved.forEach (t -> map.remove (t));


Il n'y a aucun moyen de faire cela dans le même hashmap. Créez une réplique de la carte de hachage existante, puis supprimez les éléments de la copie.


@ BorisPavlović J'utilise java 7


A moins que ce ne soit pas votre vrai code, notez que les positions, les calculs de début et de fin pourraient se faire avant la boucle ... Dans ce cas, tout le problème devient beaucoup plus simple.


@sart puis parcourez toBeRemoved dans une boucle for ...


Vous pourriez (ou devriez) avoir break; après i.remove (); . Je ne sais pas pourquoi vous laisseriez la boucle intérieure continuer dans ce cas


@assylias Je ne sais pas comment le calcul de début et de fin pourrait être effectué avant la boucle car je voudrais faire ces calculs pour chaque entrée.


@sart mais vous n'utilisez pas e ou next pour calculer ces valeurs ...


@assylias vous avez raison


@ernest_k cela a fonctionné quand j'ai utilisé la pause; Je vous remercie!


Alors, après avoir confirmé ce que @assylias a dit, quelle est la question? L'insertion d'un break transforme effectivement la boucle interne en code un bloc exécuté une seule fois, ce qui est possible car le bloc de code interne ne dépend pas de la variable de boucle, mais en fait, il n'en a même pas besoin la boucle extérieure. Vous n'avez besoin d'effectuer ce calcul qu'une seule fois, car son résultat ne change jamais, et si true , appelez clear () sur la carte . Mais vous devriez vraiment réfléchir à la manière dont vous êtes arrivé à la solution à double boucle pour évaluer une condition immuable. Il semble y avoir une énorme erreur de logique dans votre application.


Est-ce que cela répond à votre question? Itérer dans une collection, en évitant ConcurrentModificationException lors de la suppression d'objets dans une boucle


4 Réponses :


0
votes

Vous supprimez des éléments de la collection via l'itérateur i tout en l'itérant avec un itérateur différent, celui implicite utilisé par votre boucle foreach.

Vous allez toujours avoir ce problème si vous avez des itérations imbriquées sur la même collection et essayez de supprimer des éléments de la boucle interne. L'utilisation de l'itérateur interne ou externe pour supprimer l'élément de la collection produit une ConcurrentModificationException à partir de l'autre itérateur.

Puisque vous utilisez i pour supprimer l'élément, la meilleure stratégie ici est probablement de sortir de la boucle interne après avoir appelé remove .


0 commentaires


1
votes

Voici une méthode qui n'implique pas de deuxième carte ou liste et augmente également la lisibilité de votre code:

Extrayez votre condition dans une méthode spearate:

Map<String, String> filteredMap = map.entrySet().stream()
    .filter(entry -> myCondition(entry, map))
    .collect(Collectors.toMap(Entry::getKey, Entry::getValue));

Utilisez les flux java8 pour filtrer la carte en fonction de votre condition:

private boolean myCondition(Entry<String, String> currentEntry, Map<String, String> map) {
    for (Entry<String, String> entry : map.entrySet()) {
        ...
        if (...) {
            return true;
        }

        return false;
    }
}


0 commentaires

1
votes

Pour la sécurité de votre code, java ne vous permet pas de supprimer les éléments qui appartiennent à votre structure de données pendant que vous l'itérez. Une façon de le faire est de: cloner votre hashmap, itérer dans la carte de copie et faire la comparaison dessus. si la condition indique qu'un élément doit être supprimé, essayez de le supprimer de votre carte de hachage d'origine.


0 commentaires