Monday, 25 June 2018

Java 8 Optional Example - isPresent(), OrElse() and get()

The Optional class in Java is one of many goodies we have got from the Java 8 release. If you use correctly, Optional can result in clean code and can also help you to avoid NullPointerException which has bothered Java developer from its inception. Even though many of us have used null to indicate the absence of something, the big problem is that if you call a method or access a field on the null object (except static fields), you will get a NullPointerException and your whole program may crash. The bigger problem is to find the faulty code or root cause because NullPointerException only indicates the line when you try to access field or variable from a null object but how does that null is get created on the code is unknown.

I have seen many developer spending nights finding the source of dreaded NullPointerException. Thankfully some of those problems can be resolved by correctly using Optional class.

Oracle Java Certification, Oracle Java Learning, Oracle Java Tutorials and Materials

The biggest benefit of using Optional class is that it improves the readability of code. Now, you don't need to guess whether a value is present or not. Optional itself indicate that a value may be present.

Optional is nothing but a container, you can also view it as a Stream of one or none values. Now, let's see some examples of Optional class to write clean code in Java.

Suppose, we need to write a method which takes a letter and return the first book starting with that letter in the library. If there is no book found for that letter we return null.

package tool;

import java.util.Arrays;
import java.util.List;

/**
 * Program to demonstrate how to use Optional in Java 8
 *
 * @author WINDOWS 8
 *
 */
public class Hello {
  private static List<String> listOfBooks = Arrays.asList("Effective Java",
      "Clean Code", "Test Driven");

  /*
   * Return the first book start with a letter.
   */
  public static String getBook(String letter) {
    String found = null;
    for (String book : listOfBooks) {
      if (book.startsWith(letter)) {
        found = book;
        break;
      }
    }

    return found != null ? found : "Book not Found";
  }
}

You can replace the null check in this method using Optional.get() and Optional.isPresent() method and imperative code with the new Java 8 functional code using Stream API.

Anyway here is our modified Java program using the Optional feature of Java 8:

package tool;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;

/**
 * Program to demonstrate how to use Optional in Java 8
 *
 * @author WINDOWS 8
 *
 */
public class Hello {
  private static List<String> listOfBooks = Arrays.asList("Effective Java",
      "Clean Code", "Test Driven");

  /*
   * Return the first book start with a letter.
   */
  public static String getBook(String letter) {
    Optional<String> book
          = listOfBooks.stream()
                       .filter(b -> b.startsWith(letter))
                       .findFirst();

    return book.isPresent() ? book.get() : "Book Not Found";
  }
}

What we have done here is instead of using String to represent a book, we have used Optional<String> which means the variable may or may not contain a book.

We have also used new Stream API to convert our imperative style code to new Java 8 functional style. Since Stream API returns Optional it makes it easy to explain the example.

Anyway, if you look closely, the new check is not better than the old null check. If you compare, the old one was even shorter and cleaner. So, we are not really using Optional in the right way. That's actually the main problem for Java developers who have not understood the Optional concept fully.

Instead of using ifPresent() and get(), it's better to use OrElse() method which can return a default value if Optional doesn't contain a value. Using plain get() is not an option because it either return value or null.

Anyway, by using orElse() method we can rewrite the above code as shown below, which is much more cleaner and expressive.

/*
   * Return the first book start with a letter.
   */
  public static String getBook(String letter) {
    Optional<String> book
          = listOfBooks.stream()
                       .filter(b -> b.startsWith(letter))
                       .findFirst();

    return book.orElse("Book Not Found");
  }

You can see that OrElse() method is much nicer than the combination of isPresent() and get(). It not only remove the check but also more expressive e.g. either return a book or else a specified String.

And here is the screenshot of a complete program to use Optional in Java 8  for your reference:

Oracle Java Certification, Oracle Java Learning, Oracle Java Tutorials and Materials

The Optional API is also rich and provide a couple of useful methods like ifPresent() and orElseThrow() which can be used to throw an Exception if the value is not present.

That's all about how to use the Optional class in Java 8. Even though it's a poor cousin of Scala's Option type and Haskel's Maybe type, you can still write cleaner code and avoid NullPointerException if used correctly. Don't just use it blindly otherwise you would end up with poor code, sometimes worse than plain null checks.

Related Posts