Fast-Fail : meaning that if they detect
that the collection has changed since iteration began, they throw the unchecked
ConcurrentModificationException
.
I have written a test example to demonsterate this:
String hi = "Hi";
list.add(hi);
list.add("Buy");
System.out.println("list before: " + list);
for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) {
String string = iterator.next();
list.add("Good");
}
the output is:
list before: [Hi, Buy]
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859)
at java.util.ArrayList$Itr.next(ArrayList.java:831)
at thread.CollectionTest.main(CollectionTest.java:19)
which is expected. However, when an element is removed, the exception is not thrown:
List<String> list = new ArrayList<>();
String hi = "Hi";
list.add(hi);
list.add("Buy");
System.out.println("list before: " + list);
for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) {
String string = iterator.next();
list.remove(hi);
}
Output:
list before: [Hi, Buy]
list after: [Buy]
Why is that? both cases the list is modified.
Fail-Fast systems abort operation as-fast-as-possible exposing failures immediately and stopping the whole operation. Whereas, Fail-Safe systems don't abort an operation in the case of a failure. Such systems try to avoid raising failures as much as possible.
Fail-fast iterators checks the modCount flag whenever it gets the next value (i.e. using next() method), and if it finds that the modCount has been modified after this iterator has been created, it throws ConcurrentModificationException.
The Fail Fast iterators immediately throw ConcurrentModificationException in case of structural modification of the collection. Structural modification means adding, removing, updating the value of an element in a data collection while another thread is iterating over that collection.
Both Vector and ArrayList use growable array data structure. The iterator and listIterator returned by these classes (Vector and ArrayList) are fail-fast. They both are ordered collection classes as they maintain the elements insertion order.
The point is that it is not hasNext()
that checks for modification, but next()
. In your "remove" scenario, you suppress the next
call that would throw because there is no next element.
If you had 3 elements in the beginning, removing one would result in hasNext
to be 'true'. Then the following next
will throw the expected exception.
The JavaDoc points out that the "fail-fast" functionality works based on "best effort" and that it shall be used merely for detecting bugs rather than really depending on it for the program to behave correctly. Obviously because of side-effects like this one.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With