FOR loop is no longer cool

The 8th version of Java introduced a few really cool features. My favorites are streams and, connected with them, lambda expressions. In this article, I’ll show you some examples of refactoring existing code into the more modern version. All of the examples, except the 1st one, were inspired by the Aksesi Proxy source code.

I would like to remind you that all of the sources are available in my Github repository. Moreover, in the README file, you can find short project description with its main assumptions.

Stop using the  for loop

As I mentioned before, this example hadn’t been done in the last refactoring session because the final code had been already written. I’m describing it as an introduction.

Case 1: we have a map of converters where a converted class acts as a key and a converter as a value. We want to write a method which returns a list of available converters so we have to map the map into a list.

Before Java8 we would write a simple loop:

How to read it? “Create a list which will be returned as a result. For each of map entries, take its value, convert and append it to the result object”.

But now we have streams, so let’s use it:

We can read it like: “for each of map entries, get its value and convert all of them into a list”.

Case 2: we have a list of password elements (gestures or characters) and we want to process each of them using an appropriate converter. The first version of code looked like:

To understand what this method is doing we need a while. At the beginning, a result object is created and for each of gestures, we try to get a converter and perform a conversion. As a result, we return a concatenated converters outputs.

How the same solution would look like with Java8?

“For each of the password’s elements that we can convert (we have appropriate converter – filter part) apply the conversionFunction (we don’t care what it does). Concatenate all of the results using Collectors.joining()”. With the approach like this, we don’t have to know what the conversionFunction does so we can concentrate on the flow rather than implementation. The conversionFunction as an argument takes a PasswordElement, converts it using an appropriate converter and returns conversion result.

Case 3: we have a set of classes annotated with @Representation (for more information about this annotation read “Cleaning” post) and we want to register all of them using  TargetClassProvider. The register() method does not return any value.

The very first solution:

Typical for loop with some reflection-related magic i.e. looking for every class annotated with annotationClass, retrieving the annotation value, and object registration.

We can replace this awful loop with 2 lines of code:

Well, maybe not exactly 2, a little bit more because we have to implement Consumer interface ( ClassRegistrationLogic class):

You can ask why we cannot implement this logic like the one in the 2nd case. The answer is because we need TargetClassProvider object to delegate registration. We can also write it by implementing BiConsumer interface:

Honestly, I don’t know which solution is better but I haven’t found any more appropriate interfaces that can be used in a problem like this one.

Ctrl + R, replace “ obj == null” with “”

Since Java8 we can write import java.util.Optional and it will compile. Seriously.  The  Optional class should be used in every method which can possibly return the null value. Using it we reduce the probability of a  NullPointerException. Reason enough to use it frequently. Example time, code from case 2:

First of all, let’s refactor coversionFunction:

We wrapped a result with the Optional class. The most important, instead of returning the null we return Optional.empty(). If we changed returned value, we have to refactor all places where the function is used:

Before concatenation, we are checking whether a value is present ( Optional::isPresent) if so then we are merging results.

There are two tricky lines:

We used the Optional to do not perform null checks, so what is going on? The  Optional class provides a lot of methods, one of them is called get():

get() is the simplest but also the last safe of these methods. It returns the wrapped value if present but throws a NoSuchElementException otherwise. For this reason, using this method is almost always a bad idea unless you’re really sure the optional contains a value. In addition, it’s not much of an improvement over nested null checks. – Java8 in Action

Instead of get() we can use one of following methods   orElse , orElesGet, orElseThrow. The final solution:

Problem solved.

 

To sum everything up, Java8 introduced a few really cool features. I covered only the simplest ones. If you are curious what else was changed, I would recommend you to read the official documentation. At first glance, 8th version seems to be very nice and fresh, but before you will start using it in a production code, watch the video below. Trisha said several very important things about reasons behind refactoring to Java8. Additionally, performance problems were analyzed.

You may also like