We know Java has fail-fast and fail-safe iteration design.
I want to know , why we need these basically. Is there any fundamental reason for this separation? . What is the benefit of this design?.
Other than collection iteration , Java follows this design anywhere else?
Thanks
For a programmer it is useful that a code, if it contains a bug, tries to fail as fast as possible. The best would be at compile time but that is sometimes not possible.
Because of that an error can be detected earlier. Otherwise it could happen that an error remains undetected and is contained in your software for years and nobody notices the bug.
So the goal is to detect errors and bugs as early as possible. Methods that accept parameters therefore should immediately check if they are within allowed range, this would be a step towards fail-fast.
Those design-goals are everywhere, not just at iterations, simply because it is a good idea. But sometimes you want to make a trade-off with the usability or other factors.
As an example the Set
implementations allow null
values which is the source for many bugs. The new Java 9 collections do not allow this and immediately throw an exception when trying to add such, this is fail-fast.
Your iterators are also a nice example. We have some fail-fast iterators, they do not allow modifications to the collection while iterating it. The main reason is because it could easily be the source of errors. Thus they throw a ConcurrentModificationException
.
In the special case of iterations someone needs to specify how things should work. How should the iteration behave when a new element comes or gets removed while iterating? Should it be included/removed in the iteration or should it be ignored?
As an example, ListIterator
provides a very well-defined option to iterate List
and also manipulate it. There you are only allowed to manipulate the object the iterator is currently at, this makes it well-defined.
On the other side there are some fail-safe iteration methods like using a ConcurrentHashMap
. They do not throw such exceptions and allow modifications. However they work on a copy of the original collection which also solves the "how" question. So changes on the map are not reflected in the iterator, the iterator completely ignores any changes while iterating. This comes at an increased cost, a complete copy must be created each time you iterate.
For me personally those fail-safe variants are not an option. I use the fail-fast variants and memorize what I want to manipulate. After the iteration has finished I execute those memorized manipulations.
This is less comfortable to write for the programmer but you get the advantage of fail-fast. This is what I meant with trade-off with usability.