The Optional object type in Java was introduced with version 8 of Java. It is used when we want to express that a value might not be known (yet) or it's not applicable at this moment. Before Java 8 developers might have been tempted to return a null value in this case.

Ultimately, there are two scenarios for Optional:

  • Case 1: An empty box in which there is no value - Optional.empty().
  • Case 2: A box in which there is a value X - Optional.of(X).

Let's have an example. What's our car gas mileage?

  • Unknown / not applicable if we haven't driven our car yet (Case 1).
  • 30 mpg if we have traveled 30 miles with 1 gallon (Case 2).

So how could we express this with a method and an Optional? Here is an example:

Optional<Integer> getMGP(int miles, int gallons) {
	if (miles == 0) {
		return Optional.empty();
	}
		return Optional.of(miles / gallons);
}

Next, if we want to use it:

System.out.println(getMGP(100, 3));
//prints Optional[33]
System.out.println(getMGP(0, 3));
//prints Optional.empty

As we've pointed, Optional is like a box, so to "unpack" this box and get the value inside, we have to use its get() method like this:

Optional<Integer> mpg = getMGP(100, 3);

if (mpg.isPresent()) {
	System.out.println(mpg.get()); // prints 33
} else {
	System.out.println("MPG is not available yet.");
}

Note that the isPresent() method is used before we try to get the mpg value. If we try get() on an empty Optional we'll get java.util.NoSuchElementException:

Exception in thread "main" Optional.empty
java.util.NoSuchElementException: No value present
	at java.util.Optional.get(Optional.java:135)
	at testing.Test.main(Test.java:22)

To make our lives easier, Optional has a few additional methods:

  • ifPresent(Consumer c) - if the value is present, execute a consumer. With this we can rewrite the above if like this:

mpg.ifPresent(x -> System.out.println(x));

  • orElse(T other) - return a different value if there is no value. Note that if there is a value, it will be returned. For example, return 0 if there is no value:

mpg.orElse(0);

  • orElseGet(Supplier s) - if there is no value, then execute a supplier. For example, return 0:

mpg.orElseGet(() -> 0)

  • orElseThrow(Supplier s) - if there is no value, throw an exception, e.g. IllegalStateException:

mpg.orElseThrow(() -> new IllegalStateException())

That's the beauty and power of Optional. As we know from the clean code paradigms, null values shouldn't be returned so use Optional instead.