Why Iterator.next() throws ConcurrentModificationException [duplicate]
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();
}
精彩评论