Java Optional – Quick Intro and Best practices.

Java Optional was introduced in Java 1.8. Imagine Optional as a container that can hold objects and it could be empty sometimes.

Initialize an Optional.

We can initialize an empty Optional with Optional.empty(). Avoid using null to initialize an Optional. It is not a good practice.

Optional<Customer> customer = null; //Not a good practice.
Optional<Customer> customer = Optional.empty(); //An empty Optional.
Optional<Customer> customer = Optional.of(new Customer("John")); //with value
Get value from an Optional
  • Using orElse method.

To get value from an Optional most of the time we can use orElse method. When the Optional is empty using get() method will trigger java.util.NoSuchElementException

public static void main(String[] args) {
   Optional<Customer> customer = Optional.empty();
   System.out.println(customer.get());  //NoSuchElementException
}

Result:
Exception in thread "main" java.util.NoSuchElementException: No value present
	at java.base/java.util.Optional.get(Optional.java:143)

Instead use orElse method as shown below.

public static void main(String[] args) {
   Optional<Customer> customer = Optional.empty();
   System.out.println(customer.orElse(null)); //print null
   Optional customer1 = Optional.of(new Customer("john"));
   System.out.println(customer1.orElse(null)); //print Customer John.
}
  • Using orElseGet method.

Don’t use orElse method for getting a value that involves heavy computing. Because the code in orElse method gets executed even if the Optional is not empty. Consider the below code. Here even though the object is available in cache, orElse executes the getFromDB method as we can see from the output. It is not good for performance.

public static void main(String[] args) {
   Customer customer =
   getFromCache().
     orElse(getFromDB().
              orElseThrow(() ->
                 new RuntimeException("Customer Not found")));
   System.out.println(customer);
}

public static Optional<Customer> getFromCache(){
    System.out.println("getFromCache");
    return Optional.of(new Customer("From Cache"));
}

public static Optional<Customer> getFromDB(){
    System.out.println("getFromDB");
    return Optional.of(new Customer("From DB"));
}

//OUTPUT//

getFromCache
getFromDB
Customer{name='From Cache'}

If we change the above code to use orElseGet as shown below, getFromDB method will not be executed if the object is available in Cache.

Customer customer =
getFromCache().
  orElseGet(()->getFromDB().
           orElseThrow(() ->
              new RuntimeException("Customer Not found")));
System.out.println(customer);

//OUTPUT//
getFromCache
Customer{name='From Cache'}

Note: orElseGet method accepts a Supplier.

  • Do computation on value if present in Optional.

To do some computation on values of an Optional if present, use ifPresent(Consumer<? super T> action) method.

Optional<Customer> customer = Optional.of(new Customer("John"));
customer.ifPresent((c)->System.out.println(c.getName().length()));
Throw Exception if Optional is empty.

Use orElseThrow method to throw Exception if the Optional is empty.

Customer customer = getFromDB().
        orElseThrow(()->new RuntimeException("Customer Not Found"));
System.out.println(customer);

Reference: https://blogs.oracle.com/javamagazine/12-recipes-for-using-the-optional-class-as-its-meant-to-be-used

%d bloggers like this: