2010-11-13 16 views
1

J'ai une liste de ListIterator<PointF> comme champ de classe. Je le remplis dans la méthode grow(). Lorsque j'essaie d'utiliser les itérateurs de cette liste, j'obtiens ConcurrentModificationException.Java: Impossible de modifier la liste des itérateurs

ListIterator<ListIterator<PointF>> i = mPoints.listIterator(); 
while (i.hasNext()) { 
    ListIterator<PointF> j = i.next(); 
    if (j.hasNext()) 
     PointF tmp = j.next(); // Exception here 
} 

Je ne sais pas pourquoi ce code provoque exeption dans toute méthode en plusgrow()

+0

Veuillez poster un programme court mais complet qui démontre le problème. –

+0

@Jon Skeet le problème est résolu, j'ai modifié ma liste 'mPoints' après l'obtention des itérateurs. – Heheid

Répondre

4

Si la liste change sous-jacents, l'itérateur qui a été obtenu avant que ConcurrentModificationException lancers francs. Donc, ne stockez pas les itérateurs dans les champs d'instance.

0

Ce que nous pouvons dire avec certitude, c'est qu'un ConcurrentModificationException signifie que l'itératif sous-jacent a été modifié à un certain moment après votre appel pour obtenir l'itérateur.

Cela ne signifie pas toujours simultané comme dans multithread; on peut facilement déclencher cette exception en itérant à travers une liste et en supprimant des éléments pendant la boucle. Donc, s'il n'y a pas d'autres threads pouvant potentiellement le modifier, alors nous pouvons dire que le thread actuel a modifié la structure de données sous-jacente d'un itérateur à un moment donné.

Il n'y a pas assez de code ici pour être sûr, mais votre pratique de stockage des itérateurs est un peu suspecte. Quand avez-vous ajouté les itérateurs (internes) à mPoints? Si la collection à laquelle ils font référence change à tout moment après la création de l'itérateur, elle lèvera cette exception lorsqu'elle sera invoquée. Par conséquent, dès que vous ajoutez un itérateur à la collection mPoints, la structure de données de l'itérateur est effectivement verrouillée pour les modifications, mais cela ne sera pas du tout clair dans le code.

Je suppose donc que c'est la cause première de votre problème. Sauf pour un très court terme (et généralement dans une portée lexicale unique, par exemple une seule invocation de méthode), il est probablement une mauvaise idée de stocker itérateurs pour la raison que vous voyez. Il pourrait être préférable de stocker une référence aux collections sous-jacentes elles-mêmes, puis créer les itérateurs pendant le bloc de code ci-dessus, quelque chose comme:

ListIterator<Iterable<PointF>> i = mPoints.listIterator(); 
while (i.hasNext()) { 
    Iterator<PointF> j = i.next().iterator(); 
    if (j.hasNext()) 
     PointF tmp = j.next(); 
} 

à nouveau, puis la solution exacte dépend de l'architecture générale de votre méthode. La principale chose à garder à l'esprit est ne stocke pas les itérateurs à long terme, car il est presque impossible de faire ce travail de manière fiable. Même si cela fonctionne actuellement, cela crée une sorte de dépendance invisible entre les différentes parties de votre code qui sera presque invariablement brisée par quelqu'un qui implémente ce qui devrait être un changement trivial.