Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Failing Fast With Java 8

DZone's Guide to

Failing Fast With Java 8

Let's focus on Java Iterators and lambda expressions to see how you can work the vaunted fail-fast mentality into your code while avoiding hiccups.

· Java Zone ·
Free Resource

Get the Edge with a Professional Java IDE. 30-day free trial.

Fail fast or fail early is a software engineering concept that tries to prevent complex problems from happening by stopping execution as soon as something that shouldn't happen, well, happens.

In a previous blog post and presentation, I go more into detail about the merits of this approach, but in this blog post, I will just detail another use of this idea in Java 8.

In Java, Iterators returned by Collection classes, e.g. ArrayList, HashSet, Vector, etc., are fail fast. This means that if you try to add() or remove() from the underlying data structure while iterating it, you get a ConcurrentModificationException. Let's see:

import static java.util.Arrays.asList;
List<integer> ints = new ArrayList<>(asList(1,2,3,4,5,6,9,15,67,23,22,3,1,4,2));
     
for (Integer i: ints) {
    // some code
    ints.add(57);  // throws java.util.ConcurrentModificationException
}
</integer>


In Java 8u20, the Collections.sort() API is also fail fast. This means you can't invoke it inside an iteration either. For example:

import static java.util.Arrays.asList;
List<integer> ints = new ArrayList<>(asList(1,2,3,4,5,6,9,15,67,23,22,3,1,4,2));

for (Integer i: ints) {
    // some code
    Collections.sort(ints); // throws java.util.ConcurrentModificationException
}
</integer>


This makes sense. Iterating over a data structure and sorting it during the iteration is not only counter-intuitive, but it's likely to lead to unpredictable results. Now, you can get away with this and not get the exception if you have a break immediately after the sort invocation.

import static java.util.Arrays.asList;
List<integer> ints = new ArrayList<>(asList(1,2,3,4,5,6,9,15,67,23,22,3,1,4,2));
 
for (Integer i: ints) {
    // some code
    Collections.sort(ints); // throws java.util.ConcurrentModificationException
    break;
}
</integer>


But that's hardly great code. Try to avoid old-school iterations and use Lambdas when you can. But if you are stuck, just do the sort when outside the iteration

import static java.util.Arrays.asList;
List<integer> ints = new ArrayList<>(asList(1,2,3,4,5,6,9,15,67,23,22,3,1,4,2));
Collections.sort(ints);
     
for (Integer i: ints) {
    // some code
}
</integer>


Or use a data structure that sorts when you add.

This behavior of the Collections.sort() API came in Java 8 release 20. It is worth having a look at the specific section that details the change in the API:

Area: core-libs/java.util.collections

Synopsis
: Collection.sort defers now defers to List.sort

Previously Collection.sort copied the elements of the list to sort into an array, sorted that array, then updated list, in place, with those elements in the array, and the default method List.sort deferred to Collection.sort. This was a non-optimal arrangement.

From 8u20 release onwards Collection.sort defers to List.sort. This means, for example, existing code that calls Collection.sort with an instance of ArrayList will now use the optimal sort implemented by ArrayList.

I think it would have helped if Oracle were a little more explicit here on how this change could cause runtime problems. Considering everybody who uses the Collections framework, if an API that previously didn't throw an exception now can for the same situation (bad code and all that it is), it would have been better if the release notes had made it easier for developers to find that information out.

Get the Java IDE that understands code & makes developing enjoyable. Level up your code with IntelliJ IDEA. Download the free trial.

Topics:
java ,fail fast ,java 8 ,iterator ,lambda expressions ,collections api ,tutorial

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}