EP14 – How to upgrade your code to Java 8

Upgrading to Java 8It’s one thing to understand the new coding concepts and paradigms with Java 8, but it’s another thing entirely to know the best way to upgrade your existing code.

I’ve been hard at work creating a new platform that hosts all of my courses called Proffesso.com. I started coding this app using Java 7, and then started learning about all the cool Java 8 features.

So this app I built was more or less “complete” for version 1.0 before I decided to upgrade it to Java 8.

So all of these tips are based on recent real world experience.

For Loops No More

One upgrade that I’ve seen lots of availability for is to replace any of your for loops with streams.

Now this doesn’t work in ALL cases, as sometimes complex nested for loops are tough to convert over to the Java 8 Streams API, but for the most part it’s a quick win.

One example of this upgrade could be seen in a Controller where I was populating two lists.

  1. ActiveCourses
  2. NonActiveCourses

The purpose of these two lists were to keep track of which courses a particular student had paid for, and which courses they may have cancelled (or maybe their last payment attempt had failed).

If the course was active, then it would be accessible to the student, if it was NOT active, then they shouldn’t have access to the course. Simple.

Here’s what the Java 7 code looked like:

List<Offer> offers = user.getOffers();
List<Course> activeCourses = new ArrayList<>();
List<Course> nonActiveCourses = new ArrayList<>();

for (Offer offer : offers)
{
  if (isActive(offer))
    activeCourses.addAll(offer.getCourses());
  else
    nonActiveCourses.addAll(offer.getCourses());
}

nonActiveCourses.removeAll(activeCourses);

So the details of this are as follows.

An Offer contains a List of Courses. An Offer also contains the data needed to determine if all the courses in the Offer are active or not active.

The caveat here is that a Course can belong to many Offers, so if a Course is active in one Offer but not active in another, then they should still have access to that Course… Hence the second part of the code where we remove active Courses from the nonActiveCourse list.

Now, since we have some for loop madness going on here, this code is a prime candidate for Java 8 Streams.

Let’s have a look at the upgraded code:

List<Offer> offers = user.getOffers();

List<Course> activeCourses = offers.stream()
                                   .filter(offer -> isActive(offer))
                                   .map(Offer::getCourses)
                                   .flatMap(Collection::stream)
                                   .collect(Collectors.toList());
List<Course> nonActiveCourses = offers.stream()
                                      .filter(offer -> !isActive(offer))
                                      .map(Offer::getCourses)
                                      .flatMap(Collection::stream)
                                      .collect(Collectors.toList());

nonActiveCourses.removeAll(activeCourses);

Now, this particular scenario was a fairly complex one as the functionality of the Course object was dependent on a property on the Offer object (its parent).

So although our Java 8 solution is “technically” only 3 lines of code, the performance is worse because we are iterating over the offers one extra time (compared to the Java 7 solution).

So there can be an argument that an increase in readability of the code is worth the extra performance hit. But since this performance hit doesn’t tend to occur with most Java 8 upgraded code, it’s not too big a deal.

Having said that, the purpose of this tutorial is to talk about how to spot possible Java 8 upgrades, not the discussion of whether or not you SHOULD do the upgrade.

Again, in most cases, you SHOULD do the upgrade.

So all in all, whenever you see a for loop, there’s always a possibility of upgrading to Java 8.

Null Checks

The next candidate for Java 8 upgrades comes when you see the dreaded “null check”.

For example:

Offer offer = offerRepo.findOne(offerId);

if (offer == null)
  throw new OfferNotFoundException();

This is the type of code that you’ll see all over the place.

You try to load an object, but before you can use that object, you always need to deal with the null case. Because if the object comes back as null for any reason, and you try to perform a dot operation on that object, you’ll get a NullPointerException.

Boooooooooo.

So the solution is to do a “null check”.

The good news is that you can now upgrade this code with Java 8.

Anytime you see a null check, just substitute Java 8’s Optional keyword like so:

Offer offer = Optional.ofNullable(offerRepo.findOne(offerId)).orElseThrow(() -> new OfferNotFoundException());

Ahhh, fancy!

Now, this particular example throws an exception in the case of a null being returned from our repository call… but what happens if you don’t want to throw an exception?

You can just return a default value like so:

Offer offer = Optional.ofNullable(offerRepo.findOne(offerId)).orElse(new Offer());

The key is, whenever you see code that says if (something == null), you’re ready to giggle like a little school girl and drop some Java 8 Optional on that bad boy.

Summary

So those are the main things to look out for in your code-base. If you know of any other “quick wins” when it comes to upgrading to Java 8, let me know in the comments section below.