DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Because the DevOps movement has redefined engineering responsibilities, SREs now have to become stewards of observability strategy.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Related

  • Writing DTOs With Java8, Lombok, and Java14+
  • Redefining Java Object Equality
  • Addressing Memory Issues and Optimizing Code for Efficiency: Glide Case
  • Singleton: 6 Ways To Write and Use in Java Programming

Trending

  • How To Build Resilient Microservices Using Circuit Breakers and Retries: A Developer’s Guide To Surviving
  • AI Agents: A New Era for Integration Professionals
  • Securing the Future: Best Practices for Privacy and Data Governance in LLMOps
  • Useful System Table Queries in Relational Databases
  1. DZone
  2. Coding
  3. Languages
  4. Your Guide to Java 8 Optional

Your Guide to Java 8 Optional

It's never too late to dive into Java 8 goodies. Let's take a look!

By 
Shatakshi Dixit user avatar
Shatakshi Dixit
·
Updated Feb. 04, 20 · Presentation
Likes (10)
Comment
Save
Tweet
Share
56.3K Views

Join the DZone community and get the full member experience.

Join For Free

One of the most common exceptions Java programmers face is the NullPointerExceptions. This exception is thrown by the JVM at runtime as a runtime exception.

As we all know, a NullPointerException occurs when the application requires an object but it found a null value. Null value cases are one of the most common exceptions overlooked by Java programmers.

You may also like: 26 Reasons Why Using Optional Correctly Is Not Optional

Null values need to be handled in the application before proceeding with the usual business logic to avoid this exception at runtime. This leads to unnecessary null checks.

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

What Is the Problem Without Java 8 Optional?

According to Oracle, 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 the java.util package.

Let’s check out the problem without Java 8 Optional.

Suppose we have the following method in our application. This method retrieves the employee details from the database and returns it for the respective id :

Java




x


 
1
Employee findEmployee(String id) {
2
 ...
3
};



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

Java




x


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



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

How Do Java 8 Optionals Provide the Solution?

Now, let us see how Java 8 Optional will solve the above problem and help in eliminating the  NullPointerException.

Below is the modification required for the above code :

Java




x


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



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

Now, in the client’s application, this fact needs to be explicitly communicated.

The client should be written as follows:

Java




x


 
1
Optional < Employee > optional = findEmployee("1234");
2
optional.ifPresent(employee -> {
3
 System.out.println("Employee name is " + employee.getName());
4
})



You can see that 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.

The method ifPresent() in the above code snippet calls the provided lambda expression only if the employee is present; otherwise, it does not.

Advantages of Java 8 Optional

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

  • NullPointerException is prevented at runtime.
  • Null value checking is not required in the application.
  • Boilerplate code is not required.
  • It's easy to develop clean and neat APIs.

Java 8 Optional Class Methods

Methods Description
public static <T> Optional<T> empty() This method returns an empty Optional object. No value is present for this Optional.
public static <T> Optional<T> of(T value) This method returns an Optional with the specified value that 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, it 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 a 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 not a 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, then 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 returns the result of the invocation.
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X extends Throwable If 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 it exists. Otherwise, it returns 0 (zero) .
public String toString() This method is simply used to return a non-empty string representation of the Optional, which is suitable for debugging.

Creating a Java 8 Optional Object

In this section, we are going to look at the different ways we can create the Java 8 Optional object:

1. Create an empty Optional object

The code below shows how to create an Optional object that has a null value. It simply describes the absence of a value.

Java




x


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



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

The code below shows how to create an Optional object that has a non-null value.

Java




x


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



It is important to note that if null is supplied to the argument of Optional.of(), then it will throw the NullPointerException immediately and will not allow you to create the Optional object.

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

The code below shows how to create an Optional object that is allowed to have both null and non-null values.

Java




x


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



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

Checking the Presence of a Value in Java 8 Optional Object

Now, let's learn the different ways to check the presence of a value in the Java 8 Optional object through different methods:

1. isPresent() method

The method isPresent() returns the value true in case the id of the Optional objects contains a non-null value. Otherwise, it returns a false value.

Java




x


 
1
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 pass 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:

Java




x





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



In the code above, we have supplied the lambda function as the 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 the value is not present, then it throws the exception NoSuchElementException.

Java




xxxxxxxxxx
1


 
1
Employee employee = optional.get()



In the case of the absence of a value, it throws an exception, so it is recommended that before using the  get() method, we should first check if the value is present or not.

Returning the Default Value From Java 8 Optional Object Using orElse() Method

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

See the example below:

Java




xxxxxxxxxx
1


 
1
// 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:

Java




xxxxxxxxxx
1


 
1
// 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 learned, the method orElse() returns one default value directly in case the Optional object is empty, but theorElseGet() method accepts a Supplier and that Supplier is invoked when Optional is empty.

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

Java




x


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



Throw an Exception if the 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 the specified request parameter does not exist in the REST API. You can use this method to throw custom exceptions like ResourceNotFound(), etc.:

Java




x


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


Filter the Values Using Filter() Method of Optional

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


Below is the old approach for doing so:

Java




x




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



Now, let us see how can we use Optional filter to achieve this:

Java




x




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



The filter() method takes a predicate as a parameter. In case the Optional is containing a non-null value and 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 want to print its location depending upon a specified condition.


Consider the below example:

We have the getAddress()method in our Employee class :

Java




x


 
1
Address getAddress() {
2
 return this.address;
3
}



Below is the typical approach to achieve the requested scenario:

Java




x


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



Now see how we can use the map() method of Optional to achieve the same results:

Java




x


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



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

Let’s understand the code in greater detail:

Java




xxxxxxxxxx
1


 
1
// Extracting the Employee address using map() method. Optional<Address> addressOptional = employeeOptional.map(Employee::getAddress) 
2
// filtering the address from USA Optional<Address> usaAddressOptional = addressOptional.filter(address -> address.getCountry().equalsIgnoreCase("USA")); 
3
// 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 the employee is not present in employeeOptional.
  2. If the employee is present but the method getAddress() returns null.


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


Cascading Optionals Using flatMap()

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


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

It will be incorrect as we will have a problem in the following line of code if we return the Optional<Address>:

Java




x



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



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

This is further demonstrated below:

Java




xxxxxxxxxx
1


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



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

Java




xxxxxxxxxx
1


 
1
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 learned what Java 8 Optional is, its advantages, and problems solved by using Optional in Java. Additionally, we were able to better understand different methods of Java 8 Optional by looking at some illustrative examples.

Thanks for reading!

Further Reading

Java 8 Optional Uses and Best Practices

26 Reasons Why Using Optional Correctly Is Not Optional

Java 8 Optional: Handling Nulls Properly

Java (programming language) Object (computer science)

Published at DZone with permission of Shatakshi Dixit. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Writing DTOs With Java8, Lombok, and Java14+
  • Redefining Java Object Equality
  • Addressing Memory Issues and Optimizing Code for Efficiency: Glide Case
  • Singleton: 6 Ways To Write and Use in Java Programming

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!