1. Introduction
Those who are coding in Java know that null reference which results in NullPointerException
is a big problem. Optional
class was introduced in Java SE 8. This class is available in java.util
package. Optional
is a container object which may or may not contain a non-null value.
This class has a method isPresent()
which returns true
if there is a value present, otherwise false.
This is a value-based class and should be used on the basis of value. Use of reference equality (==), identity hash code, or synchronization on instances of Optional
may have unpredictable results and should be avoided.
2. What is the problem that Optional solves ?
Look at the following line of code:
String city = student.getAddress().getCity().getCityCode();
Here, the purpose of the code is obvious. We are trying to get city code of the city in which student lives.
But this piece of code may result in NullPointerException
if the student or the address or the city is null. So what to do? We usually do like this:
String city = null; if(student != null){ Address address = student.getAddress(); if(address != null){ City city = address.getCity(); if(city != null){ String cityCode = city.getCode(); } } }
As you can see, this style of code looks ugly with nested checks. There may be more nested checks depending upon logic and this result in more boilerplate code. This reduces the readability of the code.
3. What is the alternate solution?
Those who have worked on Angular should have used safe navigation operator. This is written like this:
String cityCode = student?.address?.city?.cityCode
This syntax means, cityCode is null if address is null or student is null or city is null.
In Java 8, the solution is Optional.
Java SE 8 introduces a new class called java.util.Optional<T>
. Just to understand, you can think of Optional
class as a single valued box, which may or may not contain a value.
Now let’s write our previous code with Optional
.
import java.util.Optional; class Student { private Optional<Address> address; public Optional<Address> getAddress() { return address; } public void setAddress(Optional<Address> address) { this.address = address; } } class Address { private Optional<City> city; public Optional<City> getCity() { return city; } public void setCity(Optional<City> city) { this.city = city; } } class City { private String cityCode; public String getCityCode() { return cityCode; } public void setCityCode(String cityCode) { this.cityCode = cityCode; } }
As you can see, Student has Optional<Address>
return type. Address now has Optional<City>
as return type. This style of coding has advantage over null check as developer has now to think of the case when value is present or not. Optional
class provides specific methods to check whether the value is present or not. The purpose of the Optional
class is not to replace every null check with Optional
.
Following is the solution with using Optional.
String version = student.flatMap(Student::getAddress) .flatMap(Address::getCity) .map(City::getCityCode) .orElse("Unknown");
We’ll discuss this syntax and methods in the following sections.
4. How to create Optional object
Following are the methods to create Optional objects.
static <T> Optional<T> empty() | Returns an empty Optional instance. |
static <T> Optional<T> of(T value) | Returns an Optional with the specified present non-null value. |
static <T> Optional<T> ofNullable(T value) | Returns an Optional describing the specified value, if non-null, otherwise returns an empty Optional. |
Let’s see some brief examples.
4.1 To create an empty Optional object
Optional<Address> optionalAddress = Optional.empty();
4.2 To create an Optional with non-null value
Address address = new Address();
Optional<Address> ad = Optional.of(address);
This method throws NullPointerException
if value is null
.
4.3 To create an Optional with a value which may be null
Optional<Address> ad = Optional.ofNullable(address);
If address is null, this method will return empty Optional object.
5. Return a default value using Optional
Optional
has a method orElse
which can be used to return default value.
Address addr = student.getAddress().orElse(Address.EMPTY);
In this example, Address.EMPTY
is the value to be returned if student.getAddress()
is not present. EMPTY
is the field of Address class which represents empty Address
object.
6. Throw exception if value is not present
Optional
provide a method orElseThrow
which can be used to throw exception if value is not present.
student.getAddress().orElseThrow(NoAddressFoundException::new);
Important points about Optional class
- The
Optional
class is a container class which may or may not contain a value. - The biggest advantage of using
Optional
is to avoidNullPointerException
. Optional
class has a methodisPresent()
which returnstrue
if there is a value present, otherwisefalse
.Optional
class has a methodget()
which returns the value if the value is present. If the value is not presentNoSuchElementException
is thrown.- This is a value-based class and should be used on the basis of value. Use of reference equality (==), identity hash code, or synchronization on instances of
Optional
may have unpredictable results and should be avoided. Optional
class has two methodsempty()
andof(T value)
methods which are used to returned emptyOptional
instance andOptional
instance with the specified present non-null value.- Just like stream,
Optional
class also providesfilter(..)
,map(..)
andflatMap(..)
methods.