Learnitweb

Java 8 Optional

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 avoid NullPointerException.
  • Optional class has a method isPresent() which returns true if there is a value present, otherwise false.
  • Optional class has a method get() which returns the value if the value is present. If the value is not present NoSuchElementException 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 methods empty() and of(T value) methods which are used to returned empty Optional instance and Optional instance with the specified present non-null value.
  • Just like stream, Optional class also provides filter(..), map(..) and flatMap(..) methods.