Reputation: 16676
I am in a very peculiar state. I have a list something like below :-
List<String> list = new ArrayList<String>();
list.add("a");
list.add("b");
Now when i do multiple type of traversing, like using advanced for, iterator, and normal for loop, below are the sample code snippets :-
1> Advanced Loop :-
try {
for(String a : list) {
System.out.println(a);
list.add("f");
}
} catch (Exception e) {
e.printStackTrace();
}
2> Iterator :-
try {
Iterator<String> itr = list.iterator();
while(itr.hasNext()) {
System.out.println(itr.next());
list.add("f");
}
} catch (Exception e) {
e.printStackTrace();
}
3> Normal Loop :-
for (int i=0;i<list.size();i++) {
System.out.println(list.get(i));
list.add("f");
}
Now, the peculiar problem is, that when using advanced for-loop and iterator, i get the following exception : -
java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
at java.util.ArrayList$Itr.next(Unknown Source)
the reason i know, that while iterating through a list, one cannot modify it parallely.
but when i use the normal for loop, then it works properly, Am i missing something??
Please Help!!!..
Upvotes: 4
Views: 19324
Reputation: 2411
List<String> list = new ArrayList<String>();
list.add("a");
list.add("b");
Iterator<String> itr = list.iterator();
while(itr.hasNext()) {
System.out.println(itr.next());
itr.add("f");
}
Instead of directly using the list object. you can use add(),remove() of the Iterator() class to resolve this error in ArrayList().
Instead of using List<String> list = new ArrayList<String>();
use
List<String> list = new CopyOnWriteArrayList<String>();
The main reason is ArrayList is not thread safety whereas CopyOnWriteArrayList is thread safety.
java docs reference:
ArrayList -https://docs.oracle.com/javase/8/docs/api/java/util/ArrayList.html
CopyOnWriteArrayList-https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CopyOnWriteArrayList.html
If you have follow the above approach then all the code snippets will work.
Upvotes: 0
Reputation: 91
You should keep in mind that the ConcurrentModificationException is thrown by the Iterator's next method, but not by the List's add method. This means, the list is actually modified when you add a new element in the loop. If you quit the loop after adding a new element, there is no exception thrown and the element is added to the list.
Otherwise you can use Iterator's add and remove method to modify the list inside the loop.
Upvotes: 0
Reputation: 22741
Doing a for loop on the list will create serious problems. You'll get entries being re-read (deleting a previous entry might cause this) and you might get IndexOutOfBoundsExceptions. Use CopyOnWriteArrayList for a concurrent-safe list with not that much overhead, depending on your application. If you have many writes to the list, use ConcurrentLinkedQueue, but be aware that this acts like a queue and you can only do queue-like stuff with it like only adding to the end and removing from the front.
Upvotes: 0
Reputation: 25150
If you modify a List, it invalidates any Iterator objects created from it. The advanced loop (1) compiles to nearly the same code as the iterator loop (2), meaning that there is an Iterator object created behind the scenes.
The javadocs for ConcurrentMOdificationException have more details.
If you want to add while iterating, use
ListIterator listIter = ...
while(listIter.hasNext())
{
if(shouldAdd(iter.next())) {
iter.add(....)
}
}
Upvotes: 7
Reputation: 64177
The advanced loop is just syntactic sugar for the iterator. The iterator always calls checkForComodification()
whenever it runs next()
. This method will throw an exception if it sees that you modified the list.
Running the "Normal Loop" does not provide this functionality of checking the modification count because you aren't using an iterator to loop, you are strictly using the for loop construct.
Upvotes: 3