开发者

Java: Can not change list of iterators

开发者 https://www.devze.com 2023-01-24 17:36 出处:网络
I have a list of ListItera开发者_开发百科tor<PointF> as a class field. I fill it in method grow(). When i try to use iterators from this list i get ConcurrentModificationException.

I have a list of ListItera开发者_开发百科tor<PointF> as a class field. I fill it in method grow(). When i try to use iterators from this list i get ConcurrentModificationException.

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

I have no idea why does this code causes exeption in any method besides grow()


If the underlying list changes, the iterator that was obtained before that throws ConcurrentModificationException. So don't store iterators in instance fields.


What we can say for sure is that a ConcurrentModificationException means that the underlying iterable has been modified at some point after your call to get the iterator.

This does not always mean concurrent as in multi-threaded; one can easily trigger this exception by iterating through a list and deleting elements during the loop. So, if there are no other threads potentially modifying this, then we can say that the current thread has modified an iterator's underlying data structure at some point.

There's not enough code here to be sure, but your practice of storing iterators is a little suspicious. When did you add the (inner) iterators to mPoints? If the collection they refer to changes at any time after the iterator was created, it will throw this exception when invoked. Hence as soon as you add an iterator to the mPoints collection, the iterator's data structure is effectively locked for changes, and yet this won't be very clear in the code at all.

So I suspect this is the root cause of your problem. Unless it's for a very short term (and usually within a single lexical scope, e.g. a single method invocation) it's probably a bad idea to store iterators for the reason you're seeing. It might be better to store a reference to the underlying collections themselves, and then create the iterators during the code block above, something like:

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

Then again the exact solution depends on the general architecture of your method. The main thing to bear in mind is don't store iterators long-term, because it's almost impossible to make this work reliably. Even if it does work right now, it creates a kind of invisible dependency between different parts of your code that will almost invariably be broken by someone implementing what should be a trivial change.

0

精彩评论

暂无评论...
验证码 换一张
取 消