Optional Class in Java
![Java Course - Mastering the Fundamentals](https://www.scaler.com/topics/images/instructor-tarun.webp)
Overview
Optional class introduced in Java 8 provides a clean, better, and correct way of Java programming by forcing programmers to handle the values that could be null. Before Java 8, developers depended on if-else blocks to act on variables that might hold a null reference. Often, developers forget the check resulting in the so-called NullPointerException and the application crashes unwantedly during runtime.
What is an Optional Class in Java 8 ?
Consider a situation where you want to return a list based on a condition. Let's say you want to get a list of all the individuals (living in some place in a country other than India) who are Indians. Such a list may or may not exist, i.e., in this case, value (the list of individuals) may be present or absent. When the value is absent you may use an optional value to represent its absence.
You would say that null can be returned as an optional value. But by returning null via methods you are hiding the fact about the value's presence. This null reference is a source of many problems. You could call a method on it unknowingly, and as a result, your program terminates abruptly, throwing a NullPointerException.
Even if you handle such cases by appropriate null checks using if-else, you would be compromising your code's readability.
To understand this better, consider the following example :
Output :
In the above code, you can see not only the code readability is compromised (due to nested if-else checks) but also that it is difficult to understand.
This is where Optionals in Java 8 shine. Optional allows you to store the information about presence or absence of values. Optional is a wrapper or container class in Java 8, included in the java.util package, that encapsulates an alternative value. It can be used to deal with NullPointerException as it provides various methods for checking the presence or absence of a value. It can also be used to perform actions or throw custom exceptions based on the value it contains.
Class Declaration
The Optional class is declared in such a way that its instance acts as a container object which may or may not contain a non-null value. If a value is present, isPresent() will return true and get() will return the value.
Additional methods that depend on the presence or absence of a contained value are provided, such as orElse() (return a default value if value not present) and ifPresent() (execute a block of code if the value is present).
It is a value-based class; the use of identity-sensitive operations (including reference equality (==), identity hash code, or synchronization) on instances of Optional may have unpredictable results and should be avoided.
The Optional class declaration is as follows in java.util package :
The Optional is a generic class which accepts a type parameter T. It also uses a final modifier meaning other classes cannot inherit it and describes that the class implementation is complete.
Program Using Optional Class in Java 8
1. Java Program Without Using Optional Class
Output :
Explanation :
When we use the Integer class to create an array of size 10 all the entries are assigned nulls. So when we try to call a method for the 5th number to obtain its primitive int value it throws a NullPointerException as the intValue method cannot be called on a null.
2. Java Program Using Optional Class
Output :
Explanation :
Instead of directly accessing the 5th number from the array, we first create an Optional<Integer> object using the static method ofNullable. This method returns an Optional that describes the supplied value (nums[4]) if it is not null. Otherwise, it will return an empty Optional object. The isPresent instance method in the if returns true if the value is present otherwise false when the value is null or not present.
Optional Class in Java 8 Methods
1. Static Factory Methods
Static methods belong to the class and are callable without creating an object of the class.
Method | Description |
---|---|
empty() | Returns an empty Optional instance. No value is present for this Optional. |
of(T value) | Returns an Optional describing the specified value, if non-null, otherwise returns an empty Optional. Throws NullPointerException if the value is null |
ofNullable(T value) | Returns an Optional describing the specified value, if non-null, otherwise returns an empty Optional. |
2. Instance Methods
Instance methods are callable only after the object of the Optional type is created.
Method | Description |
---|---|
equals(Object obj) | Indicates whether some other object is "equal to" this Optional. |
filter(Predicate<? super T> predicate) | If a value is present, and the value matches the given predicate, returns an Optional describing the value, otherwise returns an empty Optional. |
flatMap(Function<? super T,Optional<U>> mapper) | If a value is present, apply the provided Optional-bearing mapping function to it, and return that result, otherwise return an empty Optional. |
get() | If a value is present in this Optional, returns the value, otherwise throws NoSuchElementException. |
hashCode() | Returns the hash code value of the present value, if any, or 0 (zero) if no value is present. |
ifPresent(Consumer<? super T> consumer) | If a value is present, invoke the specified consumer with the value, otherwise do nothing. |
isPresent() | Return true if there is a value present, otherwise false. |
map(Function<? super T,? extends U> mapper) | If a value is present, apply the provided mapping function to it, and if the result is non-null, return an Optional describing the result. |
orElse(T other) | Return the value if present, otherwise returns the other. |
orElseGet(Supplier<? extends T> other) | Return the value if present, otherwise invoke other and return the result of that invocation. |
orElseThrow(Supplier<? extends X> exceptionSupplier) | Return the contained value, if present, otherwise throw an exception to be created by the provided supplier. |
toString() | Returns a non-empty string representation of this Optional suitable for debugging. |
Note :
This is about equals(Object obj). The other object is considered equal if :
- it is also Optional and,
- both instances have no value present or,
- the present values are "equal to" each other via equals().
Examples for Optional Class in Java 8
Consider the following Person class for subsequent examples :
1. Creating Optional Objects
Output :
Explanation :
You can create an Optional object of type Person by providing it as a type parameter to Optional. Empty method can be used directly to create an Optional instance that is empty. The of method takes as an argument the value for which the Optional is created and that must be non-null otherwise it will throw NullPointerException. ofNullable method is less restrictive for whether the value is present or absent, it returns an empty Optional instance if the value provided is null and otherwise, gives an Optional containing that value.
2. Checking for Values and Doing Something if Value is Present : isPresent() Vs ifPresent()
Output :
Explanation :
The isPresent method returns a boolean depending on the value's presence. If the value is present it returns true otherwise false. However, using isPresent is similar to performing manual null-checks using if-else, so this is not the recommended use of Optional.
ifPresent makes the code shorter and more readable. It takes as input a lambda expression of type Consumer or method reference which will be executed on the value only if it is present, i.e., a conditional action is executed with ifPresent.
3. Using Alternate Values if Value is not Present : orElse() and orElseGet()
Output :
Explanation :
orElse and orElseGet work similarly for returning an alternative (default) value if no value is present in the Optional object but has a subtle difference. The method provided in the orElse always gets executed no matter what value is stored in the Optional object. On the other hand, orElseGet accepts a lambda expression of the Supplier type and gets invoked if and only if the value is absent in the Optional object.
Therefore, orElseGet performs much better than orElse.
4. Optional Value Transformation With map() & flatMap()
Output :
Explanation :
The map returns the result of the computation (toLowerCase method) wrapped inside Optional if there's a value present. Otherwise, it returns an empty Optional. It works differently than flatMap, which is map transforms values only when they are unwrapped, whereas flatMap takes a wrapped value and unwraps it before transforming it.
5. Conditionally Returning Values With a filter()
Output :
Explanation :
The Optional values are filtered using the filter method that accepts a lambda expression of type Predicate that will store the appropriate check. If the Predicate condition matches for a number (i.e., returns true) then the corresponding value wrapped inside the optional is returned otherwise, an empty Optional is returned.
Conclusion
- Optional class in Java 8 is used to avoid NullPointerException.
- It is a wrapper class that encapsulates the absence or presence of values.
- It forces programmers to think about the case when the value is not present and take appropriate steps for handling it.
- Various factory methods make it easy to create Optional objects quickly, these are empty, of, and ofNullable.
- Instance methods allow many flexible operations to be performed on Optional objects.
- ifPresent helps in knowing the presence of value and isPresent assists to execute a conditional action.
- orElse and orElseGet are useful for getting alternate or default values when value is absent (null). Prefer orElseGet if you want an increased performance.
- map is used for Optional transformation and flatMap also works similarly but flattens (reduces the number of times a value is wrapped inside Optional) the wrapped values.
- filter makes use of Predicate to impose a condition on the wrapped value and return the appropriate Optional based on the predicate.
- Using the Optional class in Java 8 increases the overall readability of your program by eliminating the need for null checks.