Java 8 Optional Complete Tutorial With Examples

In this article of Java, We will understand the Java 8 Optional. Optional is a new class which was introduced in java.util package in Java version 8.

Other Programming languages has already concept similar to Optional and it has been adapted in Java .

E.g. Scala language has one feature Optional[T] , Haskell has type Maybe , which is similar to Java Optional.

In this tutorial, We will explain Java 8 Optional type with multiple illustrative examples.

Introduction to Java 8 Optional

One of the most common exception which Java programmers faces is NullPointerExceptions. This exception is thrown by the JVM at runtime as this is a Runtime Exception.

As we all know, NullPointerException occurs when application is requiring object but it found null value. This is one of the most common exception as programmers often overlook null value cases.

Null values needs to be handled in the application before proceeding with the usual business logic to avoid this exception at Runtime and this leads to unnecessary null checks.

To deal with the such type of boilerplate code for null values in Java, a new type Optional<T> was introduced in Java version 8.

Java 8 Optional Complete Tutorial With Examples

What is the Problem Without Java 8 Optional?

Java 8 Optional works as a container type for the value which is probably absent or null. Java Optional is a final class present in java.util package.

Let’s understand the problem without the Java 8 Optional :

Suppose, we have below method in our application and this method retrieves the employee details from the database and returns it for the respective id :

Employee findEmployee(String id) { ... };

Suppose the provided id is not present in the database then the method will return the null value. Now if we have code as written below :

Employee employee = findEmployee("1234");
System.out.println("Employee's Name = " + employee.getName());

The code above will straightforward throw the NullPointerException at Runtime as the programmer has not null checked the value before using it.

How Java 8 Optionals provide the solution?

Now , let us see How Java 8 Optional will solve the above described problem and helps in removing the NullPointerException .

Below is the modification requires in above code :

Optional<Employee> findEmployee(String id) { ... };

In the above code, we are indicating to the client by returning Optional<Employee> that there is a possibility that there may not exist any employee with the given id.

Now , In client’s application this fact needs to be explicitly forces. See How :

The client should be written as below :

Optional<Employee> optional = findEmployee("1234");

optional.ifPresent(employee -> {
    System.out.println("Employee name is " + employee.getName());    
})

You can see, we have created one Optional object in the above code’s first line. Now we are allowed to use various utility methods with the optional object.

Method ifPresent() in the above code snippet call the provided lambda expression only if the employee is present otherwise not.

Advantages of Java 8 Optional

Below are some of the listed advantages of Java 8 Optional :

  • NullPointerException are prevented at run-time.
  • Null value checking is not required in the application.
  • Boilerplate code not required.
  • Easy to develop clean and neat APIs.

Java 8 Optional Class Methods

MethodsDescription
public static <T> Optional<T> empty()This method returns an empty Optional object. None value is present for this Optional.
public static <T> Optional<T> of(T value)This method returns an Optional with the specified value which is not null.
public static <T> Optional<T> ofNullable(T value)This method returns an Optional describing the specified value, if the value is non-null, otherwise returns an empty Optional.
public T get()If a value is present in this Optional then it returns the value otherwise it throws NoSuchElementException.
public boolean isPresent() This method returns true value if there is a value present otherwise it returns false.
public void ifPresent(Consumer<? super T> consumer)If a value is present then the consumer with the provided value is invoked otherwise it does nothing.
public Optional<T> filter(Predicate<? super T> predicate)If a value is present and it also matches the given predicate then it returns an Optional describing the value otherwise it returns an empty Optional.
public <U> Optional<U> map(Function<? super T,? extends U> mapper)If a value is present then the mapping function is applied and if the result is a not null value then it returns an Optional describing the result. Otherwise it returns an empty Optional.
public <U> Optional<U> flatMap(Function<? super T,Optional<U> mapper)If the value is present the it applies the provided Optional-bearing mapping function to it and it returns that result, otherwise it returns an empty Optional.
public T orElse(T other)This method returns the value if present, otherwise it returns other.
public T orElseGet(Supplier<? extends T> other)This method returns the value if present otherwise it invokes other and return the result of the invocation.
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X extends ThrowableIf the value is present, This method returns the contained value , otherwise it throws an exception to be created by the provided supplier.
public boolean equals(Object obj)This method is used for Indicating whether some other object is “equal to” this Optional or not.
public int hashCode()This method returns the hash code value of the present value, if exist otherwise it returns 0 (zero) .
public String toString()This method is simply used to return a non-empty string representation of the Optional, It is suitable for debugging.

Creating a Java 8 Optional object

In this section, Let’s understand different ways of creating the Java 8 Optional Object :

1.Create an empty Optional object

Below code shows how to create an Optional object which has null value. It simply describes the absence of a value.

Optional<Employee> employee = Optional.empty();

2.Create an Optional object with a non-null value

Below code shows how to create an Optional object which has non-null value.

Employee employee = new Employee("1234", "TechBlogStation");
Optional<Employee> optional = Optional.of(employee);

This is to be noted that, if null is supplied to argument of Optional.of() then it will throw the NullPointerException immediately and will not allow to create the Optional object.

3.Create an Optional object with a value which can be null and non-null

Below code shows how to create an Optional object which is allowed to have null and non-null value.

Optional<Employee> optional = Optional.ofNullable(employee);

If non-null value is passed in Optional.ofNullable() then it will return the Optional containing the specified value otherwise just returns an empty Optional.

Checking the presence of a value in Java 8 Optional Object

Let’s learn different ways to checking of presence of a value in the Java 8 Optional Object through different methods :

1. isPresent() method

Method isPresent() returns the value true in case id the Optional objects contains a not-null value otherwise it returns false value.

if(optional.isPresent()) {
    // Suppose the non null value is present in Optional
    System.out.println("Value - " + optional.get());
} else {
    // Suppose the null value is present in Optional
    System.out.println("Optional is empty");
}	

2. ifPresent() method

In the Method ifPresent() , we pas the Consumer function . That Consumer function will only be executed if a value is present in the Optional object.

If Optional is empty then it does nothing.

optional.ifPresent(value -> {
    System.out.println("Value present - " + value);
});

In the above code , we have supplied the lambda function as parameter of the ifPresent() method.

Retrieving the value from Java 8 Optional Object using get() method

The get() method of Optional is simply used to return a value from the Optional object. Suppose If the value is not present then it throws the exception – NoSuchElementException.

Employee employee = optional.get()

As in the case of absence of value , It throws exception so it is recommended that before using get() method we should first check is the value is present or not.

Returning the default value from Java 8 Optional Object using orElse() method

Method orElse() is used to return a default value if the Optional object is empty.

See the below example :

// Below will return "Unknown Employee" if employee is null
User finalEmployee = (employee != null) ? employee : new Employee("0", "Unknown Employee");

Now , Write the above logic using Java 8 Optional’s orElse() method:

// Below will return "Unknown Employee" if employee is null
User finalEmployee = optional.orElse(new Employee("0", "Unknown Employee"));

Returning the default value from Java 8 Optional Object using orElseGet() method

As we learnt, method orElse() return one default value directly in case the Optional object is empty but orElseGet() method accepts a Supplier and that Supplier is invoked when the Optional is empty.

The result that is returned by the Supplier becomes default value for the Optional.

User finalEmployee = optional.orElseGet(() -> {
    return new Employee("0", "Unknown Employee");
});

Throw an exception if value is not present in Java 8 Optional

The orElseThrow() method is used for throwing an exception if the Optional object is empty.

It can be used in the scenario where the object for specified request parameter does not exist in Rest API. You can use this method to throw custom exceptions like ResourceNotFound() etc.

@GetMapping("/employees/{id}")
public User getEmployee(@PathVariable("id") String id) {
    return employeeRepository.findById(id).orElseThrow(
	    () -> new ResourceNotFoundException("Employee not found with id " + id);
    );
}

Filter the values using filter() method of Optional

Suppose , you have an Optional object of Employee. Now you are checking for the gender of the employee and calling a function correspondingly.

Below is the old approach for doing it :

if(employee != null && employee.getGender().equalsIgnoreCase("MALE")) {
    // calling the function
}

Now, Let us see How can we use Optional filter to achieve this :

optional.filter(user -> employee.getGender().equalsIgnoreCase("MALE"))
.ifPresent(() -> {
    // Your function
})

The filter() method takes a predicate as parameter. In case the Optional is containing a not null value and also the value matches the provided predicate then this method returns an Optional containing that value.

Otherwise this method returns an empty Optional.

Extract and transform values using map()

Suppose , we have a scenario where we want to extract the address of an employee and also wants to print its location depending upon some condition.

Consider below example :

We have getAddress() method in our Employee class :

Address getAddress() {
    return this.address;
}

Below is the typical approach to achieve the requested scenario :

if(employee != null) {
    Address address = employee.getAddress();
    if(address != null && address.getCountry().equalsIgnoreCase("USA")) {
	    System.out.println("Employee belongs to USA");
    }
}

Now, See How we can use map() method of Optional to achieve the same results :

userOptional.map(Employee::getAddress)
.filter(address -> address.getCountry().equalsIgnoreCase("USA"))
.ifPresent(() -> {
    System.out.println("Employee belongs to USA");
});

The above code in comparison to the typical approach is well readable, concise and efficient.

Let’s understand the code in detail :

// Extracting the Employee address using map() method.
Optional<Address> addressOptional = employeeOptional.map(Employee::getAddress)

// filtering the address from USA
Optional<Address> usaAddressOptional = addressOptional.filter(address -> address.getCountry().equalsIgnoreCase("USA"));

// Printing if country is USA
usaAddressOptional.ifPresent(() -> {
    System.out.println("Employee belongs to USA");
});

In the above code snippets , the method map() is returning an empty optional in one of the following cases :

  1. If employee is not present in employeeOptional.
  2. If employee is present but the method getAddress() return null.

 Otherwise, it simply returns an Optional<Address> which contains the employee address.

Cascading Optionals using flatMap()

Now Let us again consider the above example related to map() method.

You can see even if the Employee address can be null then why are we not returning the Optional<Address> instead of simple Address extracted from getAddress() method.

It will be wrong as we will have problem in below line if we will return the Optional<Address> :

Optional<Address> addressOptional = employeeOptional.map(Employee::getAddress)

Now , the method getAddress() is returning Optional<Address> so mthe return type of employeeOptional.map() will be Optional<Optional<Address>>.

Like Below :

Optional<Optional<Address>> addressOptional = employeeOptional.map(Employee::getAddress)

Now we have nested Optional and we don’t want that so we can now use flatMap() method to solve this problem :

Optional<Address> addressOptional = employeeOptional.flatMap(Employee::getAddress)

Please note that If your mapping function is returning an Optional then use flatMap() instead of map() to get the flattened result from your Optional object.

Conclusion

We have learnt What is Java 8 Optional , Its advantage, and what problems are solved by using Optional in Java.

We also understood different methods of Java 8 Optional with some illustrative examples.

Thanks for Reading!

Leave a Reply

Your email address will not be published. Required fields are marked *