开发者

Why Iterator.next() throws ConcurrentModificationException [duplicate]

This question already has answers here: Why is a ConcurrentModificationException thrown and how to debug it (8 answers) Closed 3 years ago.

Strangly enough, this small piece of code throws the above mentioned Exception. Also, looking at code posted around the web this seems to be correct:

import java.util.ArrayList;
import java.util.Iterator;

public class IteratorTest {

    ArrayList<Integer> arr = new ArrayList<Integer>();

    Iterator i = arr.iterator();

    public void show() {
        arr.add(2);
        arr.add(5);
        arr.add(9);

        while(i.hasNext()){
            System.o开发者_C百科ut.println(i.next());
        }
    }
}

Any advice? Thanks


This call:

Iterator i=arr.iterator();

should be after you've done all the writes into your ArrayList.

So in your code do this just before you start iterating like this:

Iterator i=arr.iterator();
while(i.hasNext()) {
...
}


It's because you've modified the backing list between getting the Iterator via iterator() and calling next().

The typical usage of an Iterator is:

for (Iterator<Integer> iter=arr.iterator(); iter.hasNext(); ) {
    Integer element = iter.next();
}

Or better yet, use the new for-each loop:

for (Integer element: arr) {
}

Make sure to to perform additions to the Collection outside of the loop.


You are defining the Iterator upon instantiation of your object, IteratorTest. You then add some data to the ArrayList, arr.

You have now modified your list, and thus the Iterator's state is invalid.

You cannot use the Iterator and change the ArrayList without using the Iterator to do it.


Answer 4 is technically correct, but not because a for(;;) or "for each" loop is used instead of a while() loop. It simply a matter of the Iterator's declared scope within the Class rather than the method. First, let's look at the behavior of the two methods hasNext() and next():

The hasNext() method simply queries an internal cursor (index); next() actually advances the cursor, therefore that is the "modification" that could raise the exception. If you try to use an Iterator declared and assigned outside of the method in which next() is being used, the code will throw an exception on the first next(), regardless if it's a for(;;) or while().

In Answer 4 and 8, the iterator is declared and consumed locally within the method. It just so happens that since the for(;;) construct allows for a first time declaration and assignment of the iterator before the loop executes (which makes the iterator scoped to the for(;;) and implicitly within the method, making it "safe"). I agree that the for(;;) idiom is cleaner syntactically and fences scope at the lowest level of execution, completely within the for(;;) loop.

Answer 8 is correct, because the Iterator is assigned and used locally inside the method.

But, just for sake of the discussion, the following method using a while() statement is syntactically correct, "safe" and non-modifying from a scope and reference perspective:

somewhere in the Class definition ...

ArrayList<String> messageList;

somewhere in the class constructor

messageList = new ArrayList<String>(); 

add a method...

public printMessages ( )
{

  Iterator<String> messageIterator = messageList.iterator();

  while (messageIterator.hasNext())
     {
     System.out.println(messageIterator.next());
     }

  System.out.flush();

}
0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜