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 DSA, DBMS, Competitive Programming, Python, Java, JavaScript, etc. Also, check out some of the Guided Paths on topics such as Data Structure andAlgorithms, Competitive Programming, Operating Systems, Computer Networks, DBMS, System Design, etc., as well as some Contests, Test Series, and Interview Experiences curated by top Industry.