Why and How to Use Optional in Java
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.