When we run above program, we get java.util.ConcurrentModificationException as soon as the ArrayList is modified. It happens because ArrayList iterator is fail-fast by design. What it means is that once the iterator is created, if the ArrayList is modified, it throws a ConcurrentModificationException.
public class ConcurrentListExample {
public void someMethod() {
List<String> list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");
list.add("4");
list.add("5");
// get the iterator
Iterator<String> it = list.iterator();
//manipulate list while iterating
while (it.hasNext()) {
String str = it.next();
System.out.println(str);
if (str.equals("2")) {
list.remove("5");
}
if (str.equals("3")) {
list.add("3 found");
}
if(str.equals("4")) {
list.set(1, "4");
}
}
}
}
but if we take Employee class:
public class Test {
public static void main(String[] args) {
List al = new ArrayList();
Employee ee = new Employee(1, "anoj");
Employee ee1 = new Employee(2, "hai");
al.add(ee);
al.add(ee1);
Iterator it = al.iterator();
while (it.hasNext()) {
Employee hh = (Employee)it.next();
if (hh.getName().equals("anoj")) {
al.remove(0);
System.out.println(al);
}
}
}
}
I didn't get a ConcurrentModificationException.
You can't modify and print operations simultaneously using iterator.
it support add() and remove().
It doesn't fail on the second time because the iterator returns anoj last. So hasNext returns false and next is never called, thus no ConcurrentModificationException.
Simply move the addition of ee1 above ee and it will fail
Note This is internal implementation to ArrayList as to 1. Why anoj is returned last and 2. Why hasNext doesnt throw CME.
The check for concurrent modification exception gas a flaw that if you remove the second last element of an ArrayList it wont complain but will skip the last entry.
this happens because it checks whether it has iterated size() times before checking the concurrent modification.
I think the correct explanation is this extract from th javadocs of ConcurrentModificationExcetion:
Note that fail-fast behavior cannot be guaranteed as it is, generally
speaking, impossible to make any hard guarantees in the presence of
unsynchronized concurrent modification. Fail-fast operations throw
ConcurrentModificationException on a best-effort basis. Therefore, it
would be wrong to write a program that depended on this exception for
its correctness: ConcurrentModificationException should be used only
to detect bugs.
Related
This question already has answers here:
Iterating through a Collection, avoiding ConcurrentModificationException when removing objects in a loop
(31 answers)
Closed 8 years ago.
I'm trying to remove some elements from an ArrayList while iterating it like this:
for (String str : myArrayList) {
if (someCondition) {
myArrayList.remove(str);
}
}
Of course, I get a ConcurrentModificationException when trying to remove items from the list at the same time when iterating myArrayList. Is there some simple solution to solve this problem?
Use an Iterator and call remove():
Iterator<String> iter = myArrayList.iterator();
while (iter.hasNext()) {
String str = iter.next();
if (someCondition)
iter.remove();
}
As an alternative to everyone else's answers I've always done something like this:
List<String> toRemove = new ArrayList<String>();
for (String str : myArrayList) {
if (someCondition) {
toRemove.add(str);
}
}
myArrayList.removeAll(toRemove);
This will avoid you having to deal with the iterator directly, but requires another list. I've always preferred this route for whatever reason.
Java 8 user can do that: list.removeIf(...)
List<String> list = new ArrayList<>(Arrays.asList("a", "b", "c"));
list.removeIf(e -> (someCondition));
It will remove elements in the list, for which someCondition is satisfied
You have to use the iterator's remove() method, which means no enhanced for loop:
for (final Iterator iterator = myArrayList.iterator(); iterator.hasNext(); ) {
iterator.next();
if (someCondition) {
iterator.remove();
}
}
No, no, NO!
In single threated tasks you don't need to use Iterator, moreover, CopyOnWriteArrayList (due to performance hit).
Solution is much simpler: try to use canonical for loop instead of for-each loop.
According to Java copyright owners (some years ago Sun, now Oracle) for-each loop guide, it uses iterator to walk through collection and just hides it to make code looks better. But, unfortunately as we can see, it produced more problems than profits, otherwise this topic would not arise.
For example, this code will lead to java.util.ConcurrentModificationException when entering next iteration on modified ArrayList:
// process collection
for (SomeClass currElement: testList) {
SomeClass founDuplicate = findDuplicates(currElement);
if (founDuplicate != null) {
uniqueTestList.add(founDuplicate);
testList.remove(testList.indexOf(currElement));
}
}
But following code works just fine:
// process collection
for (int i = 0; i < testList.size(); i++) {
SomeClass currElement = testList.get(i);
SomeClass founDuplicate = findDuplicates(currElement);
if (founDuplicate != null) {
uniqueTestList.add(founDuplicate);
testList.remove(testList.indexOf(currElement));
i--; //to avoid skipping of shifted element
}
}
So, try to use indexing approach for iterating over collections and avoid for-each loop, as they are not equivalent!
For-each loop uses some internal iterators, which check collection modification and throw ConcurrentModificationException exception. To confirm this, take a closer look at the printed stack trace when using first example that I've posted:
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
at java.util.AbstractList$Itr.next(AbstractList.java:343)
at TestFail.main(TestFail.java:43)
For multithreading use corresponding multitask approaches (like synchronized keyword).
While other suggested solutions work, If you really want the solution to be made thread safe you should replace ArrayList with CopyOnWriteArrayList
//List<String> s = new ArrayList<>(); //Will throw exception
List<String> s = new CopyOnWriteArrayList<>();
s.add("B");
Iterator<String> it = s.iterator();
s.add("A");
//Below removes only "B" from List
while (it.hasNext()) {
s.remove(it.next());
}
System.out.println(s);
If you want to modify your List during traversal, then you need to use the Iterator. And then you can use iterator.remove() to remove the elements during traversal.
List myArrayList = Collections.synchronizedList(new ArrayList());
//add your elements
myArrayList.add();
myArrayList.add();
myArrayList.add();
synchronized(myArrayList) {
Iterator i = myArrayList.iterator();
while (i.hasNext()){
Object object = i.next();
}
}
One alternative method is convert your List to array, iterate them and remove them directly from the List based on your logic.
List<String> myList = new ArrayList<String>(); // You can use either list or set
myList.add("abc");
myList.add("abcd");
myList.add("abcde");
myList.add("abcdef");
myList.add("abcdefg");
Object[] obj = myList.toArray();
for(Object o:obj) {
if(condition)
myList.remove(o.toString());
}
You can use the iterator remove() function to remove the object from underlying collection object. But in this case you can remove the same object and not any other object from the list.
from here
This question already has answers here:
Iterating through a Collection, avoiding ConcurrentModificationException when removing objects in a loop
(31 answers)
Closed 8 years ago.
I'm trying to remove some elements from an ArrayList while iterating it like this:
for (String str : myArrayList) {
if (someCondition) {
myArrayList.remove(str);
}
}
Of course, I get a ConcurrentModificationException when trying to remove items from the list at the same time when iterating myArrayList. Is there some simple solution to solve this problem?
Use an Iterator and call remove():
Iterator<String> iter = myArrayList.iterator();
while (iter.hasNext()) {
String str = iter.next();
if (someCondition)
iter.remove();
}
As an alternative to everyone else's answers I've always done something like this:
List<String> toRemove = new ArrayList<String>();
for (String str : myArrayList) {
if (someCondition) {
toRemove.add(str);
}
}
myArrayList.removeAll(toRemove);
This will avoid you having to deal with the iterator directly, but requires another list. I've always preferred this route for whatever reason.
Java 8 user can do that: list.removeIf(...)
List<String> list = new ArrayList<>(Arrays.asList("a", "b", "c"));
list.removeIf(e -> (someCondition));
It will remove elements in the list, for which someCondition is satisfied
You have to use the iterator's remove() method, which means no enhanced for loop:
for (final Iterator iterator = myArrayList.iterator(); iterator.hasNext(); ) {
iterator.next();
if (someCondition) {
iterator.remove();
}
}
No, no, NO!
In single threated tasks you don't need to use Iterator, moreover, CopyOnWriteArrayList (due to performance hit).
Solution is much simpler: try to use canonical for loop instead of for-each loop.
According to Java copyright owners (some years ago Sun, now Oracle) for-each loop guide, it uses iterator to walk through collection and just hides it to make code looks better. But, unfortunately as we can see, it produced more problems than profits, otherwise this topic would not arise.
For example, this code will lead to java.util.ConcurrentModificationException when entering next iteration on modified ArrayList:
// process collection
for (SomeClass currElement: testList) {
SomeClass founDuplicate = findDuplicates(currElement);
if (founDuplicate != null) {
uniqueTestList.add(founDuplicate);
testList.remove(testList.indexOf(currElement));
}
}
But following code works just fine:
// process collection
for (int i = 0; i < testList.size(); i++) {
SomeClass currElement = testList.get(i);
SomeClass founDuplicate = findDuplicates(currElement);
if (founDuplicate != null) {
uniqueTestList.add(founDuplicate);
testList.remove(testList.indexOf(currElement));
i--; //to avoid skipping of shifted element
}
}
So, try to use indexing approach for iterating over collections and avoid for-each loop, as they are not equivalent!
For-each loop uses some internal iterators, which check collection modification and throw ConcurrentModificationException exception. To confirm this, take a closer look at the printed stack trace when using first example that I've posted:
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
at java.util.AbstractList$Itr.next(AbstractList.java:343)
at TestFail.main(TestFail.java:43)
For multithreading use corresponding multitask approaches (like synchronized keyword).
While other suggested solutions work, If you really want the solution to be made thread safe you should replace ArrayList with CopyOnWriteArrayList
//List<String> s = new ArrayList<>(); //Will throw exception
List<String> s = new CopyOnWriteArrayList<>();
s.add("B");
Iterator<String> it = s.iterator();
s.add("A");
//Below removes only "B" from List
while (it.hasNext()) {
s.remove(it.next());
}
System.out.println(s);
If you want to modify your List during traversal, then you need to use the Iterator. And then you can use iterator.remove() to remove the elements during traversal.
List myArrayList = Collections.synchronizedList(new ArrayList());
//add your elements
myArrayList.add();
myArrayList.add();
myArrayList.add();
synchronized(myArrayList) {
Iterator i = myArrayList.iterator();
while (i.hasNext()){
Object object = i.next();
}
}
One alternative method is convert your List to array, iterate them and remove them directly from the List based on your logic.
List<String> myList = new ArrayList<String>(); // You can use either list or set
myList.add("abc");
myList.add("abcd");
myList.add("abcde");
myList.add("abcdef");
myList.add("abcdefg");
Object[] obj = myList.toArray();
for(Object o:obj) {
if(condition)
myList.remove(o.toString());
}
You can use the iterator remove() function to remove the object from underlying collection object. But in this case you can remove the same object and not any other object from the list.
from here
This question already has answers here:
Why is a ConcurrentModificationException thrown and how to debug it
(8 answers)
java.util.ConcurrentModificationException not thrown when expected
(2 answers)
Closed 3 years ago.
The following Java code throws a ConcurrentModificationException, as expected:
public class Evil
{
public static void main(String[] args) {
Collection<String> c = new ArrayList<String>();
c.add("lalala");
c.add("sososo");
c.add("ahaaha");
removeLalala(c);
System.err.println(c);
}
private static void removeLalala(Collection<String> c)
{
for (Iterator<String> i = c.iterator(); i.hasNext();) {
String s = i.next();
if(s.equals("lalala")) {
c.remove(s);
}
}
}
}
But the following example, which differs only in the contents of the Collection, executes without any exception:
public class Evil {
public static void main(String[] args)
{
Collection<String> c = new ArrayList<String>();
c.add("lalala");
c.add("lalala");
removeLalala(c);
System.err.println(c);
}
private static void removeLalala(Collection<String> c) {
for (Iterator<String> i = c.iterator(); i.hasNext();) {
String s = i.next();
if(s.equals("lalala")) {
c.remove(s);
}
}
}
}
This prints the output "[lalala]". Why doesn't the second example throw a ConcurrentModificationException when the first example does?
Short answer
Because the fail-fast behavior of an iterator isn't guaranteed.
Long answer
You're getting this exception because you cannot manipulate a collection while iterating over it, except through the iterator.
Bad:
// we're using iterator
for (Iterator<String> i = c.iterator(); i.hasNext();) {
// here, the collection will check it hasn't been modified (in effort to fail fast)
String s = i.next();
if(s.equals("lalala")) {
// s is removed from the collection and the collection will take note it was modified
c.remove(s);
}
}
Good:
// we're using iterator
for (Iterator<String> i = c.iterator(); i.hasNext();) {
// here, the collection will check it hasn't been modified (in effort to fail fast)
String s = i.next();
if(s.equals("lalala")) {
// s is removed from the collection through iterator, so the iterator knows the collection changed and can resume the iteration
i.remove();
}
}
Now to the "why": In the code above, notice how the modification check is performed - the removal marks the collection as modified, and next iteration checks for any modifications and fails if it detects the collection changed. Another important thing is that ArrayList (not sure about other collections) does not check for modification in hasNext().
Therefore, two strange things may happen:
If you remove the last element while iterating, nothing will be thrown
That's because there's no "next" element, so the iteration ends before reaching the modification-checking code
If you remove the second-to-last element, ArrayList.hasNext() will actually also return false, because the iterator's current index is now pointing at the last element (former second-to-last).
So even in this case, there's no "next" element after the removal
Note that this all is in line with ArrayList's documentation:
Note that the fail-fast behavior of an iterator cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast iterators throw ConcurrentModificationException on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness: the fail-fast behavior of iterators should be used only to detect bugs.
Edited to add:
This question provides some information on why the concurrent modification check is not performed in hasNext() and is only performed in next().
If you look at the source code for the ArrayList iterator (private nested class Itr), you'll see the flaw in the code.
The code is supposed to be fail-fast, which is done internally in the iterator by calling checkForComodification(), however the hasNext() doesn't make that call, likely for performance reasons.
The hasNext() instead is just:
public boolean hasNext() {
return cursor != size;
}
This means that when you're on the second last element of the list, and then remove an element (any element), the size is reduced and hasNext() thinks you're on the last element (which you weren't), and returns false, skipping the iteration of the last element without error.
OOPS!!!!
From other answers you know what is the right way of removing an element in collection while you are iterating the collection.
I give here the explanation to the basic question.And the answer to your question lies in the below stack trace
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
at java.util.ArrayList$Itr.next(Unknown Source)
at com.ii4sm.controller.Evil.removeLalala(Evil.java:23)
at com.ii4sm.controller.Evil.main(Evil.java:17)
In the stacktrace it is obvious that i.next(); line throws the error. But when you have only two elements in the collection.
Collection<String> c = new ArrayList<String>();
c.add("lalala");
c.add("lalala");
removeLalala(c);
System.err.println(c);
When the first one is removed i.hasNext() returns false and i.next() is never executed to throw the exception
you should remove from the iterator (i) not the collection (c) directly;
try this:
for (Iterator<String> i = c.iterator(); i.hasNext();) {
String s = i.next();
if(s.equals("lalala")) {
i.remove(); //note here, changing c to i with no parameter.
}
}
EDIT:
The reason why the first try throws exception while the second one doesn't is simply because of the number of element in your collection.
as the first one will go through the loop more than once and the second one will only iterate once. therefore, it doesn't have the chance to throw exception
You can't remove from list if you're browsing it with "for each" loop.
You can't remove an item from a collection you're iterating over. You can get around this by explicitly using an Iterator and removing the item there. You can use Iterator.
If you use below code you will not get any exception :
private static void removeLalala(Collection<String> c)
{
/*for (Iterator<String> i = c.iterator(); i.hasNext();) {
String s = i.next();
if(s.equals("lalala")) {
c.remove(s);
}
}*/
Iterator<String> it = c.iterator();
while (it.hasNext()) {
String st = it.next();
if (st.equals("lalala")) {
it.remove();
}
}
}
Is there any way I can modify the HashMap values of a particular key while iterating over it?
A sample program is given below:
public static void main(String[] args) {
HashMap<Integer,ArrayList<String>> hm = new HashMap<Integer, ArrayList<String>>();
ArrayList<String> ar = new ArrayList<String>();
for(int i=0;i<50;i++){
ar.add(Integer.toString(i));
}
hm.put(1, ar);
for(String s:hm.get(1)){
hm.get(1).add("hello");
}
}
Error Thrown:
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
at java.util.ArrayList$Itr.next(Unknown Source)
at Excp.main(Excp.java:17)
This exception may be thrown by methods that have detected concurrent modification of an object when such modification is not permissible.
Below peice of code is causing the problem.
for(String s:hm.get(1)){
hm.get(1).add("hello");
}
You are iterating and modifying the same. Avoid this by creating new ArrayList
ArrayList<String> ar1 = new ArrayList<String>();
for (String s : hm.get(1)) {
ar1.add("hello");
}
have a read here
When we are trying to modify collection object while iterating then we get this exception. Check following code:
for(String str : stringList){
stringList.add("Test");
}
So in above we get runtime exception.
Solution
Use iterator over For-Each loop, like:
static void filter(Collection<?> c) {
for (Iterator<?> it = c.iterator(); it.hasNext(); )
if (!anyCondition(it.next()))
it.remove();
}
So basic difference between For-Each and iterator is, we can modify collection while iterating using only iterator.
The problem in the code your presented isn't modifying the HashMap, it's modifying the ArrayList while iterating it.
You can avoid this exception if you use ar's ListIterator instead of using an enhanced for loop:
for (ListIterator<String> i = ar.listIterator(); i.hasNext(); i.next()) {
i.add("hello");
}
If try to modify while iterating your list you will get this Exception.
for(String s:hm.get(1)){ // iterate
hm.get(1).add("hello");//modify
}
Both operation affect to hm
You don't need to iterate here. Just use
hm.get(1).add("hello");
If you want to add to the original ArrayList, then iterate through it on your own:
final ArrayList<String> arr = hm.get(1);
final int size = arr.size();
// this will add size number of "hello" strings to ArrayList arr
for(int i = 0; i < size; ++i){
// you don't appear to ever use this value
final String s = arr.get(i);
// do something to arr
arr.add("hello");
}
Although not related to the question, but just adding
ConcurrentModificationException can also occur if you get the iterator over a collection first and then add some more elements over it and then iterating over the collection will throw this exception.
For example :
package got;
import java.util.*;
public class GotCharacters {
public static void main(String... args){
Person p1 = new Person("TL", 40, "Tyrion Lannister");
Person p2 = new Person("JM", 50, "Jorah Mormont");
Person p3 = new Person("AS", 20, "Arya Stark");
//Defining the collection and adding some elements
ArrayList<Person> al;
al = new ArrayList<Person>();
al.add(p1);
al.add(p2);
al.add(p3);
//Getting the iterator
Iterator<Person> itr = al.iterator();
Royalty r1 = new Student("DT", 25, "Daenerys Targaryen", "DragonMother", "Targaryen");
Royalty r2 = new Student("JS", 28, "Jon Snow", "Lord Commander", "Targaryen");
Collection<Royalty> c = new ArrayList<Royalty>();
c.add(s1);
c.add(s2);
//Adding more elements after getting the iterator
al.addAll(c);
while(itr.hasNext()){
System.out.print(itr.next());
}
}
}
Outcome :
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
at java.util.ArrayList$Itr.next(ArrayList.java:851)
at myArrayList.ArrayList1.main(ArrayList1.java:34)
Concurrent Modification in programming means to modify an object concurrently when another task is already running over it. Fail Fast And Fail Safe Iterators in Java
Iterators in java are used to iterate over the Collection objects. Fail-Fast iterators immediately throw ConcurrentModificationException if there is structural modification of the collection. Fail-Safe iterators don’t throw any exceptions if a collection is structurally modified while iterating over it. This is because, they operate on the clone of the collection, not on the original collection and that’s why they are called fail-safe iterators.
Please use ConcurrentHashMap if you want to modify in between.
If you can use normal(Iterating over indexes) for loop you can avoid that error.
This question already has answers here:
Why is a ConcurrentModificationException thrown and how to debug it
(8 answers)
Closed 3 years ago.
I have below two java class
import java.util.*;
public class ArrayListTest032 {
public static void main(String[] ar) {
List<String> list = new ArrayList<String>();
list.add("core java");
list.add("php");
list.add("j2ee");
list.add("struts");
list.add("hibernate");
Iterator<String> itr = list.iterator();
while (itr.hasNext()) {
System.out.println(itr.next());
}
list.remove("php");
while (itr.hasNext()) {
System.out.println(itr.next());
}
}
}
When I run above code I get below output.
core java
php
j2ee
struts
hibernate
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
at java.util.AbstractList$Itr.next(AbstractList.java:343)
at ArrayListTest032.main(ArrayListTest032.java:20)
Which is expected as I am modifying the list while iterating. But in below java class same logic is executed by set family.
import java.util.*;
public class HashSetTest021 {
public static void main(String[] ar) {
Set<String> set = new HashSet<String>();
set.add("core java");
set.add("php");
set.add("j2ee");
set.add("struts");
set.add("hibernate");
Iterator<String> itr = set.iterator();
while (itr.hasNext()) {
System.out.println(itr.next());
}
set.remove("php");
while (itr.hasNext()) {
System.out.println(itr.next());
}
}
}
And out put is.
hibernate
core java
j2ee
php
struts
There is no any ConcurrentModificationException.
I just want to know why same piece of code throws ConcurrentModificationException in case of list family, but there is no any ConcurrentModificationException in case of set family
This is a kind of 'retrograde' behavior, insomuch as iterators, once fully traversed, are not reusable, aka their hasNext method should return false when you reach the end of the list.
In this case though, the iterator returned by ArrayList.iterator is an internal implementation class, with code for hasNext as follows:
public boolean hasNext() {
return cursor != size;
}
So when you call hasNext in your second loop, it indicates (falsely) that there are more items to iterate over, because you executed an operation that changed the size of the list, after the first iteration. Semantically, you should not be able to continue iterating over items in the list after you reach the end of it, but due to this implementation detail it lets you proceed with the second while loop. Of course, at that point, you get a concurrent modification exception because of the change you made in the backing list.
On the other hand, the iterator used by your hash set has its hasNext implemented as follows:
public final boolean hasNext() {
return next != null;
}
This implementation happens not to be as 'vulnerable' to modifications made to the hash set after an iteration has been completed, and as such the hasNext method is better behaved.
This is a difference in the implementation: the iterator returned by the array list detects concurrent modifications even when it is positioned at the end, because it checks the length; iterators of the HashSet, TreeSet and LinkedList, on the other hand, do not detect this condition, because they check for being positioned at the end before checking for concurrent modification. The documentation allows iterators not to throw on concurrent modifications, so both approaches are valid.
Demo for the TreeSet.
Demo for the LinkedList.
Start by reading the JavaDoc for Iterator. Does it mention ConcurrentModificationException anywhere?
Now, read the JavaDoc for ConcurrentModificationException, and note the following (emphasis added):
This exception may be thrown by methods that have detected concurrent modification of an object when such modification is not permissible.
Now look closely at your code. Your while loop iterates through all elements of the collection (even though the output of your first example doesn't indicate this, which tells me that either you've edited the output or this is not your actual code). At the time you remove the element, there are no more items to iterate, so the second loop should always exit immediately.
So, the conclusion is that the implementers of the list iterator have chosen that to throw that exception even when there are no more elements to iterate, while the implementers of the set iterator have chosen not to. Both cases are completely acceptable given the specifications.
public static void main(String[] ar) {
List<String> list = new ArrayList<String>();
list.add("core java");
list.add("php");
list.add("j2ee");
list.add("struts");
list.add("hibernate");
Iterator<String> itr = list.iterator();
while (itr.hasNext()) {
System.out.println(itr.next());
}
list.remove("php");
/* while (itr.hasNext()) {
System.out.println(itr.next());
}*/
}
problem in itr object.it holds the list object reference
Hashset can throw a ConcurrentModificationException if you do anything to the set except through the iterator. However, there are a lot of heuristics around the itertor's fast-fail behavior with the goal to complete the iteration if at all possible. The JavaDocs seem pretty clear on it's behavior.
In case of list when we traverse it with first loop
Iterator itr = set.iterator();
while (itr.hasNext()) {
System.out.println(itr.next());
}
The cursor value and size will become same.Cursor contains value for total no of elements traversed and inside hashNext() method for list traversal contains code as:
public boolean hasNext() {
return cursor != size;
}
So after first while loop cursor == size.But after removing element from list size becomes (originalSize-1).So for next while loop it goes inside while and inside itr.next() method it checks for modcount modification and throws ConcurrentModificationException.
In case of Set it checks for next != null for every itr.hasnext() call.And after traversing first while loop next becomes null.Removing element from set does not affect next value as null and itr.hasNext will return next == null as true and hence it does not go inside while loop to check modcount modification.And hence it does not throw ConcurrentModification Exception.