Table of contents
1.
Introduction
2.
Static Methods
2.1.
Optional.empty()
2.2.
Optional.of(value)
2.3.
Optional.ofNullable(value)
3.
Instance Methods
3.1.
isPresent()
3.2.
get()
3.3.
orElse(defaultValue)
3.4.
orElseThrow(exceptionSupplier)
4.
Concrete Methods
4.1.
map(mapper)
4.2.
filter(predicate)
4.3.
flatMap(mapper)
5.
Examples
5.1.
Example 1: Retrieving a value from an optional
5.2.
Example 2: Chaining operations on an optional
5.3.
Example 3: Handling absence of a value
6.
Frequently Asked Questions
6.1.
What happens if I use Optional.get() without checking if the value is present?
6.2.
Can Optional help in reducing all null-related errors?
6.3.
Is it considered bad practice to frequently use Optional.ofNullable()?
7.
Conclusion
Last Updated: Jun 19, 2024
Easy

Optional Class in Java 8

Author Rinki Deka
0 upvote
Career growth poll
Do you think IIT Guwahati certified course can help you in your career?

Introduction

In Java 8, optional classes provide a way to handle the presence or absence of values without relying on null. When we didn't have optional classes, null was often used to represent the absence of a value, but this could lead to NullPointerExceptions if not handled properly. Optional classes offer a clear & safe approach to working with values that may or may not exist. 

Optional Class in Java 8

In this article, we'll discuss what optional classes are, how to use them, & the benefits of using them in our Java code.

Static Methods

Optional classes provide several static methods that allow you to create optional objects & perform various operations on them. These methods are part of the Optional class itself & can be used without creating an instance of Optional. Here are some commonly used static methods:

Optional.empty()

This method returns an empty optional object. It represents the absence of a value.

Optional<String> emptyOptional = Optional.empty();

Optional.of(value)

This method creates an optional object with the specified non-null value. If the value is null, it throws a NullPointerException.

String name = "Ravi";
Optional<String> optionalName = Optional.of(name);

Optional.ofNullable(value)

This method creates an optional object that may contain a null value. If the value is null, it returns an empty optional.

String name = null;
Optional<String> optionalName = Optional.ofNullable(name);


Note: These static methods provide convenient ways to create optional objects based on different scenarios. They help in encapsulating the logic of handling null values & provide a clear intention when working with potentially absent values.

Instance Methods

Once you have an optional object, you can use various instance methods to interact with the value it holds or perform operations based on the presence or absence of the value. Here are some commonly used instance methods:

isPresent()

This method returns true if the optional contains a non-null value, & false otherwise.

Optional<String> optionalName = Optional.of("Rekha");
boolean isPresent = optionalName.isPresent(); // Returns true

get()

This method returns the value held by the optional if it is present. If the optional is empty, it throws a NoSuchElementException.

Optional<String> optionalName = Optional.of("Rekha");
String name = optionalName.get(); // Returns "Rekha"

orElse(defaultValue)

This method returns the value held by the optional if it is present. If the optional is empty, it returns the provided default value.

Optional<String> optionalName = Optional.empty();
String name = optionalName.orElse("Unknown"); // Returns "Unknown"

orElseThrow(exceptionSupplier)

This method returns the value held by the optional if it is present. If the optional is empty, it throws an exception provided by the exception supplier.

Optional<String> optionalName = Optional.empty();
String name = optionalName.orElseThrow(() -> new IllegalArgumentException("Name not found"));


Note: These instance methods allow you to interact with the value held by an optional object & provide default behaviors or error handling in case the optional is empty. They help in writing cleaner & more expressive code by eliminating the need for explicit null checks.

Concrete Methods

In addition to the static & instance methods, optional classes also provide concrete methods that allow you to perform various operations on the optional value. These methods enable you to transform, filter, or chain operations on optional objects. Here are a few commonly used concrete methods:

map(mapper)

This method applies the provided mapping function to the value held by the optional, if it is present, & returns a new optional containing the result of the mapping.
 

Optional<String> optionalName = Optional.of("Rinki");
Optional<Integer> optionalLength = optionalName.map(String::length); // Returns Optional.of(4)

filter(predicate)

This method tests the value held by the optional against the provided predicate if it is present. If the predicate returns true, it returns the optional; otherwise, it returns an empty optional.

Optional<Integer> optionalAge = Optional.of(25);
Optional<Integer> filteredAge = optionalAge.filter(age -> age > 18); // Returns Optional.of(25)

flatMap(mapper)

This method is similar to map(), but the provided mapper function returns an optional itself. It helps in flattening nested optional.

Optional<String> optionalName = Optional.of("Rahul");
Optional<Optional<Integer>> optionalLength = optionalName.map(name -> Optional.of(name.length()));
Optional<Integer> flattenedLength = optionalName.flatMap(name -> Optional.of(name.length())); // Returns Optional.of(4)


Note: These concrete methods provide powerful ways to manipulate & transform optional values. They allow you to write more concise & expressive code by chaining operations & avoiding explicit conditional checks.

Examples

Let's look at a few examples to see how optional classes can be used :

Example 1: Retrieving a value from an optional

Optional<String> optionalName = Optional.of("Rekha");
String name = optionalName.orElse("Unknown");
System.out.println(name); 


Output: 

Rekha


In this example, we create an optional containing the value "Rekha”. We then use the orElse() method to retrieve the value if it is present, or return a default value of "Unknown" if the optional is empty. Since the optional contains a value, it prints "Rekha".

Example 2: Chaining operations on an optional

Optional<Integer> optionalNumber = Optional.of(10);
int result = optionalNumber
        .filter(num -> num > 5)
        .map(num -> num * 2)
        .orElse(0);
System.out.println(result);


Output: 

20


In this example, we have an optional containing the value 10. We use the filter() method to check if the value is greater than 5. If it is, we proceed to the map() method, which multiplies the value by 2. Finally, we use orElse() to retrieve the result or return 0 if the optional is empty. Since the value satisfies the filter condition & is transformed by the map operation, the result is 20.

Example 3: Handling absence of a value

Optional<String> optionalValue = Optional.empty();
String result = optionalValue.orElseThrow(() -> new IllegalArgumentException("Value not found"));


In this example, we have an empty optional. We use the orElseThrow() method to throw an exception if the optional is empty. If the optional contains a value, it would be returned. However, since the optional is empty, it throws an IllegalArgumentException with the message "Value not found".

Frequently Asked Questions

What happens if I use Optional.get() without checking if the value is present?

Using get() without a prior isPresent() check can lead to a NoSuchElementException if the Optional is empty. Always ensure the presence of a value before calling get().

Can Optional help in reducing all null-related errors?

Optional can significantly reduce null-related errors by making null handling explicit. However, it's not a replacement for good null-check practices and should be used judiciously.

Is it considered bad practice to frequently use Optional.ofNullable()?

Not necessarily, but it should be used when nullability is a common scenario. Overusing Optional can lead to performance overhead and unnecessarily complex code. Use it where it makes sense to express absence of values explicitly.

Conclusion

In this article, we learned about optional classes in Java 8 & how they provide a better way to handle the presence or absence of values compared to using null. We discussed static methods for creating optional objects, instance methods for interacting with optional values, & concrete methods for transforming & manipulating optional data. Lastly, we understood a few examples, to see how optional classes can be used to write cleaner, more expressive, & maintainable code.

You can refer to our guided paths on Code 360. You can check our course to learn more about DSADBMSCompetitive ProgrammingPythonJavaJavaScript, etc. Also, check out some of the Guided Paths on topics such as Data Structure andAlgorithmsCompetitive ProgrammingOperating SystemsComputer Networks, DBMSSystem Design, etc., as well as some Contests, Test Series, and Interview Experiences curated by top Industry.

Live masterclass