Using Optional in Java to check for null

Posted by & filed under , .

I see the need for null in Java still, but since the Optional class was introduced I think some of the usages of null can be eliminated by employing some of the capabilities of the Optional class. I will explain in this post a nice way you can implement checking for null in Java by employing the Optional class. (And if you are one of the fans of the “new” functional way of writing code in Java you will find this even more so appealing! 🙂 )

To start with let’s look at a very simple example in Java: checking if a value is null and setting a value based on that result. Let’s consider for instance that given a (user) name we create a greeting to be shown to the user, customized to include the user name if present or otherwise instruct the user to log in. The typical Java code for this looks something like this:

String greeting(String userName) {
   String g;
   if( userName == null ) {
      g == "Please log in";
   } else {
      g == "Hello " + userName;
   }
   return g;
}

This follows the general “convention” that if the value for userName is passed in as null then it’s not present — and we should instead use a “default” value.

Now let’s see how we can write this using Optional:

String greeting(Optional<String> userName) {
   return userName.map(s -> "Hello " + s).orElse("Please log in");
}

Neat right? However some of you will say (rightly so) that when dealing with older libraries, they still tend to return data using the “null-based” convention where null is returned for “not present” and in such cases we still need a greeting() method which accepts a parameter as a String. In such cases we need to make only a small change — by using the power of Optional.ofNullable(), which according to the JavaDoc:

Returns an Optional describing the specified value, if non-null, otherwise returns an empty Optional.

So the above code becomes:

String greeting(String userName) {
   Optional<String> un = Optional.ofNullable(userName);
   return un.map(s -> "Hello " + s).orElse("Please log in");
}

This now leads us to more interesting ways we can chain these null checks:

String greeting() {
   String userName = authenticationSystem.getUsername(); // this can return null if user not logged in
   Optional<String> un = Optional.ofNullable(userName);
   return un
            .map(user -> workflowSystem.getAllPendingItemsForUser(user))
            .map((List<Items> items) -> "You have " + items.size() + " waiting in your inbox")
            .orElse("Please log in");
}

Believe it or not this is the equivalent of this (lengthy) method:

String greeting() {
   final String logIn = "Please log in";
   String userName = authenticationSystem.getUsername(); // this can return null if user not logged in
   if( userName == null ) return logIn;
   List<items> = workflowSystem.getAllPendingItemsForUser(userName);
   if( items == null ) return logIn;
   return "You have " + items.size() + " waiting in your inbox";
}

The cool thing about using Optional is that when using map(), this takes care already of the possibility of returning null, similar to Optional.ofNullable; the JavaDoc reads for this:

If a value is present, apply the provided mapping function to it, and if the result is non-null, return an Optional describing the result.

So if your lambda / code used in the map() returns null, the result will be an Optional.empty() which then prevents the rest of the chain executing and we go straight to the orElse(). This way you can chain a few of null checking transparently all hanging off the initial Optional! And the beauty of it is that you don’t have to explicitly write code to check for value being null / present, it’s all done for you by the class.

Imagine (taking this to the extreme now) a scenario where you have something like this:

public String compute(String a) {
    String b;
    String c;
    String d;
 
    if (a == null) {
        b = "123";
    } else {
        b = f1(a);
    }
 
    if (b == null) {
        c = "abc";
    } else {
        c = f2(b);
    }
 
    if (c == null) {
        d = "xyz";
    } else {
        d = f3(c);
    }
 
    return d;
}

This can be written more compact like this:

public String compute(String a) {
    String b;
    String c;
    String d;
 
    b = (a == null) ? "123" : f1(a);
    c = (b == null) ? "abc" : f2(b);
    d = (c == null) ? "xyz" : f3(c);
 
    return d;
}

The above code can be modelled with an Optional like this (f1, f2 and f3 are methods of the current class obviously):

public String compute(String a) {
    String b;
    String c;
    String d;
 
    b = Optional.ofNullable(a).map(this::f1).orElse("123");
    c = Optional.ofNullable(b).map(this::f2).orElse("abc");
    d = Optional.ofNullable(c).map(this::f3).orElse("xyz");
 
    return d;
}

This one looks a bit more difficult to write using Optional, so let’s look at another example:

public String compute(String a) {
   String b = (a == null) ? null : f1(a);
   String c = (b == null) ? null : f2(b);
   String d = (c == null) ? null : f3(c);
   return d;
}

Now this one looks very cool when chaining again Optional.map:

public String compute(String a) {
   return Optional.ofNullable(a).map(this::f1).map(this::f2).map(this::f3).orElse(null);
}

As with everything there are pros and cons — for instance I haven’t figured out a more elegant way of dealing with complicated if/else “cascades” like the one shown earlier — however I highly recommend migrating code “cascades” from null to Optional, you have to admit it looks more elegant.

Leave a Reply

Your email address will not be published.