I know that if the Collection will be changed while some thread is traversing over it using iterator, the iterator.next() will throw a ConcurrentModificationException.
But it shows different behavior depending on the number of elements in the list.
I tried a code snippet in which I traversed a list in for-each loop and in between it's traversal removed an element from the list using remove() method of the list.
Ideally it should throw a ConcurrentModificationException in this condition without depending on number of elements in the list, But it is not true when number of elements in list are two.
Case 1: Number of elements in list - 1
public static void main(String[] args)
{
List<String> list=new ArrayList<String>();
list.add("One");
for (String string : list)
{
System.out.println(string);
list.remove(string);
}
}
Output: One
Exception in thread "main" java.util.ConcurrentModificationException
That's was as expected.
Case 2: Number of elements in list - 2
public static void main(String[] args)
{
List<String> list=new ArrayList<String>();
list.add("One");
list.add("two");
for (String string : list)
{
System.out.println(string);
list.remove(string);
}
}
Output: One
No Exception is thrown?????????
Case 3: Number of elements in list - 3
public static void main(String[] args)
{
List<String> list=new ArrayList<String>();
list.add("One");
list.add("Two");
list.add("Three");
for (String string : list)
{
System.out.println(string);
list.remove(string);
}
}
Output: One
Exception in thread "main" java.util.ConcurrentModificationException
Again an exception is thrown which is ideal behavior.
But why it runs properly in case-2 without throwing any ConcurrentModificationException.
From the documentation (emphasis mine):
The iterators returned by this class's
iterator
andlistIterator
methods are fail-fast: if the list is structurally modified at any time after the iterator is created, in any way except through the iterator's ownremove
oradd
methods, the iterator will throw aConcurrentModificationException
. Thus, in the face of concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic behavior at an undetermined time in the future.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.