EP12 – Java 8’s New Optional Keyword

Java 8 Optional KeywordNullPointerExceptions are a royal pain in the butt. They can strike at almost any point if your code encounters any “edge cases” that you hadn’t previously thought of.

And when a NullPointerException is thrown, it can severely impact the quality of your user’s experience.

For something as simple as “Hey, there’s nothing here”, it’s amazing how serious a problem this can be.

Well, that’s where Java 8 has stepped up their game and finally provided us with a keyword we can use to solve this issue.

[Enter Stage Left]: Optional

The Java 8 Optional keyword is used as a wrapper around objects (kind of like a container).

In Oracle’s tutorial on this keyword they use the example of a soundcard in a computer.

A computer can have a soundcard, or it could be missing a soundcard. So you could use the Optional keyword to get around the possible NullPointerExceptions.

Here’s a diagram that gives you an idea of what it visually looks like to use Optional:

Java 8 Optional

So, if you’re in a situation where you’re pre-Java 8, here’s how you’d have to deal with all the possible NullPointerException issues:

String version = "UNKNOWN";
if(computer != null){
  Soundcard soundcard = computer.getSoundcard();
  if(soundcard != null){
    USB usb = soundcard.getUSB();
    if(usb != null){
      version = usb.getVersion();
    }
  }
}

A pretty big mess right? We’re probably all so used to writing this kind of code to check for nulls, but it’s madness.

Java 8 Optional Syntax

So how do we write some nicer code now that we have Java 8 on our side? Let’s have a look:

public class Computer {
  private Optional<Soundcard> soundcard;  
  public Optional<Soundcard> getSoundcard() { ... }
  ...
}

public class Soundcard {
  private Optional<USB> usb;
  public Optional<USB> getUSB() { ... }

}

public class USB{
  public String getVersion(){ ... }
}

Pretty straight-forward I hope. All we’re doing here is wrapping the Soundcard and USB objects with the Optional keyword.

Fair enough, but how do we access the values? Let’s use Java 8 Streams to get the job done (Note: If you haven’t learned about Streams yet, check out this article I wrote on the subject).

List<String> usbVersions = computers.stream()
                           .flatMap(Computer::getSoundcard)
                           .flatMap(Soundcard::getUSB)
                           .map(USB::getVersion)
                           .orElse("UNKNOWN");

So what this code will do is it will extract all the usb versions from a list of Computers, but, in the case that there is no soundcard or no usb object available, it will fallback to the orElse() method.

So if a computer doesn’t have a Soundcard, or if it doesn’t have a USB, we’ll get “UNKNOWN” and NO NULLPOINTERS! Boo yah!

So really what this Optional keyword is doing, is that it’s forcing us to deal with the null case.

Creating Optional Objects

Alright, so we’ve seen how to deal with Optional objects that come from a stream.

But now let’s take a look at how to create them.

Optional<Soundcard> sc = Optional.of(new Soundcard()); 

One thing to understand here is that when you perform an Optional.of() call, the value shouldn’t be null, otherwise it will still throw a NullPointerException.

If this seems strange to you, then you will likely prefer a different method:

Optional<Soundcard> sc = Optional.ofNullable(new Soundcard());

With the Optional.ofNullable() method, if the object being passed in is null, you’ll just get an empty Optional object when you try to access the soundcard inside.

Doing Stuff with your Optional Value

Does this look familiar:

SoundCard soundcard = ...;
if(soundcard != null){
  System.out.println(soundcard);
}

Yeah, we’ve all been there. Let’s harness the power of Optional:

Optional<Soundcard> soundcard = ...;
soundcard.ifPresent(System.out::println);

Makes a lot more sense now right? If there’s a value present in the Optional wrapper, it’ll get printed out to the console. Otherwise, no worries, you’re not going to throw a stupid NullPointerException because you tried to print an empty object.

Logging just got 10 times easier and safer!

PS. you can also use a soundcard.isPresent() check that returns true if soundcard contains a value.

PPS. oh yeah, you can also just get your object from the Optional container by saying soundcard.get()… but be careful, because that could throw a NoSuchElementException if there is no object in the container.

Java 8 Optional – Default Values and Actions

Pre-Java 8 this was a common scenario:

Soundcard soundcard = 
  aSoundcard != null ? aSoundcard 
            : new Soundcard("basic_sound_card");

Let’s clean that up a bit with Java 8:

Soundcard soundcard = aSoundcard.orElse(new Soundcard("default"));

So this code reads like so… I’d like to declare a soundcard object and try to populate it with aSoundcard. If aSoundcard doesn’t have a value, then assign a default value instead.

Now if you’re new to Java 8, this might seem complicated… but it’s only unfamiliar to you, it’s actually pretty simple stuff.