J'essaie d'utiliser la boucle foreach avec l'arraylist, mais quand je l'utilise, cela me donne une erreur, mais quand j'utilise la boucle for normal, cela fonctionne parfaitement, quel pourrait être le problème?
Le code est ici:
for (Pair p2 : R) {
if ((p2.getFirstElm() == p.getSecondElm()) && (p2.getFirstElm() != p2.getSecondElm()))
R.add(new Pair (p.getFirstElm(), p2.getSecondElm()));
else if ((p2.getSecondElm() == p.getFirstElm()) && (p2.getFirstElm() != p2.getSecondElm()))
R.add(new Pair (p2.getFirstElm(), p.getSecondElm()));
// else
// There are no transitive pairs in R.
}
c'est la boucle qui ne fonctionne pas, et voici celle qui fonctionne:
for (int i = 0; i < R.size(); i++) {
if ((R.get(i).getFirstElm() == p.getSecondElm()) && (R.get(i).getFirstElm() != R.get(i).getSecondElm()))
R.add(new Pair (p.getFirstElm(), R.get(i).getSecondElm()));
else if ((R.get(i).getSecondElm() == p.getFirstElm()) && (R.get(i).getFirstElm() != R.get(i).getSecondElm()))
R.add(new Pair (R.get(i).getFirstElm(), p.getSecondElm()));
//else
// There are no transitive pairs in R.
}
l'erreur que j'obtiens lorsque j'utilise la boucle foreach est:
Exception in thread "main" Java.util.ConcurrentModificationException
at Java.util.AbstractList$Itr.checkForComodification(Unknown Source)
at Java.util.AbstractList$Itr.next(Unknown Source)
at set.problem.fourth.PoSet.makeTransitive(PoSet.Java:145)
at set.problem.fourth.PoSet.addToR(PoSet.Java:87)
at set.problem.fourth.PoSetDriver.typicalTesting(PoSetDriver.Java:35)
at set.problem.fourth.PoSetDriver.main(PoSetDriver.Java:13)
Les classes de la collection Java sont résistantes aux défaillances, ce qui signifie que si la collection est modifiée pendant qu'un thread le traverse à l'aide de l'itérateur, le
iterator.next()
lance unConcurrentModificationException
.Cette situation peut se produire dans le cas d'un environnement multithread ou à thread unique. - www.javacodegeeks.com
Vous ne pouvez pas modifier un List
dans une boucle for/each
, Qui est du sucre syntaxique autour du Iterator
comme détail d'implémentation. Vous ne pouvez appeler en toute sécurité .remove()
qu'en utilisant directement le Iterator
.
Notez que Iterator.remove est le seul moyen sûr de modifier une collection pendant l'itération; le comportement n'est pas spécifié si la collection sous-jacente est modifiée d'une autre manière pendant l'itération. - Tutoriel sur les collections Java
L'appel de .add()
dans la boucle for/each
Modifie le contenu, et le Iterator
utilisé en arrière-plan le voit et lève cette exception.
Une préoccupation plus subtile est que la deuxième façon que vous listez, le .size()
augmente à chaque fois que vous .add()
donc vous finirez par traiter toutes les choses que vous .add()
, cela pourrait éventuellement provoquer une boucle sans fin en fonction de ce que les données d'entrée sont. Je ne sais pas si c'est ce que vous désirez.
Solution
Je créerais un autre ArrayList
et .add()
pour toutes les nouvelles choses, puis après la boucle, utiliser .addAll()
sur le ArrayList
d'origine pour combiner les deux listes ensemble. Cela rendra les choses explicites dans ce que vous essayez de faire, c'est-à-dire à moins que votre intention ne traite toutes les choses nouvellement ajoutées au fur et à mesure que vous les ajoutez.
Utilisez toujours les classes de collections Immutable
et créez de nouvelles classes de collection Immutable
au lieu d'essayer d'en modifier une seule partagée. C'est essentiellement ce que dit ma réponse de 2012, mais je voulais le rendre plus explicite.
La goyave le supporte très bien, utilisez ImmutableList.copyOf()
pour faire circuler les données.
Utilisez Iterables.filter()
pour filtrer les éléments dans un nouveau ImmutableList
, sans état mutable partagé, ce qui signifie aucun problème de concurrence!
Le problème est que vous faites le R.add () dans la première ligne de la boucle.
Dans la première situation, vous avez un itérateur ouvert à l'arrayliste. Lorsque vous effectuez un ajout, puis essayez à nouveau d'itérer, l'itérateur remarque que la structure des données a changé sous vous.
Dans le cas du look for, vous obtenez simplement un nouvel élément à chaque fois et n'avez pas le problème de modification simultanée, bien que la taille change à mesure que vous ajoutez d'autres éléments.
Pour résoudre le problème, vous souhaitez probablement ajouter à un emplacement temporaire et l'ajouter après la boucle ou faire une copie des données initiales et ajouter à l'original.