Deep dive into the optional java API

Moroccan software developer, Java/Spring. Love to learn, eager to write.
Search for a command to run...

Moroccan software developer, Java/Spring. Love to learn, eager to write.
No comments yet. Be the first to comment.
Java’s threading model has long been a cornerstone of its concurrency capabilities. However, the limitations of traditional platform threads (wrappers around OS threads) have persisted for decades—until the release of java 21. Virtual threads, repres...

Introduction Hey there! Let's dive into design patterns—specifically, the Strategy Pattern. Once you get the hang of it, you'll start seeing it everywhere. The Strategy Pattern is all about defining a group of algorithms, wrapping each one up, and ma...

When evaluating the quality of your tests, most developers turn to code coverage tools. These tools provide a percentage indicating how much of your code is executed by your test suite. At first glance, this seems like the ultimate metric: higher cov...

Introduction In modern software development, data validation is important for keeping data correct and stopping incorrect input from entering a system. Spring Boot offers different ways to do data validation. However, with Java 14's new records featu...

The Magic of Modern Java

The Optional<T> class in Java is a container object that may or may not contain a value. Introduced in Java 8 as part of the functional programming enhancements, its goal is to provide a more expressive way to represent optional or absent values without relying on null references. The Optional<T> is a fundamental class in the Java Standard Library, and it's essential for developers to understand its methods, improvements, and use cases. This article provides an exhaustive guide to the class, including its methods and how they can be used effectively in your Java code.
At its core, Optional is a wrapper for a value that may or may not be present. It helps developers avoid common issues with null, such as NullPointerException, by forcing the handling of optional values.
Optional<String> optionalValue = Optional.of("Hello, Java!");
In this example, optionalValue is an Optional that contains a non-null value. If you pass null to the of method, it throws a NullPointerException. For cases where null is valid, you can use Optional.ofNullable().
Optional<String> optionalValue = Optional.ofNullable(null);
With Optional, the intent of "this value might be absent" is explicit, and handling such cases becomes more predictable and less error-prone.
Optional<T>The Optional class has a wide range of methods, each designed to handle optional values elegantly. Let's break down all the key methods and explore their purpose:
empty():
Returns an empty
Optionalinstance.
Optional<String> emptyOptional = Optional.empty();
of(T value):
Returns an
Optionalwith the specified non-null value.
Optional<String> opt = Optional.of("value");
ofNullable(T value):
Returns an
Optionaldescribing the specified value, or an emptyOptionalif the value isnull.
Optional<String> opt = Optional.ofNullable(null);
get():
If a value is present, returns the value. Otherwise, throws
NoSuchElementException.
isPresent():
Returns
trueif the value is present, otherwisefalse.
isEmpty() (Java 11):
Returns
trueif theOptionalis empty, otherwisefalse.
orElse(T other):
Returns the value if present, otherwise returns
other.
orElseGet(Supplier<? extends T> other):
Returns the value if present, otherwise calls the
Supplierand returns its result.
orElseThrow():
Returns the contained value if present, otherwise throws
NoSuchElementException.
orElseThrow(Supplier<? extends X> exceptionSupplier):
Returns the value if present, otherwise throws an exception produced by the
Supplier.
ifPresent(Consumer<? super T> action):
If a value is present, performs the given action with the value.
ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction) (Java 9):
If a value is present, performs the action with the value; otherwise, runs the
emptyAction.
map(Function<? super T, ? extends U> mapper):
If a value is present, applies the provided mapping function to it and returns a new
Optionalwith the result.
flatMap(Function<? super T, Optional<U>> mapper):
Similar to
map(), but the mapper function must return anOptional.
filter(Predicate<? super T> predicate):
If a value is present and it matches the given predicate, returns an
Optionaldescribing the value; otherwise, returns an emptyOptional.
stream() (Java 9):
If a value is present, returns a
Streamcontaining the value; otherwise, returns an emptyStream.
OptionalAvoid using Optional for fields/parameters: Optional was designed for return types and not as a type for class members or arguments for methods. Using Optional in fields/parameters can lead to unnecessary complications.
Use Optional for method return types: It's an excellent choice for methods that might return null. It forces the caller to handle the absent case explicitly.
Do not use Optional.get(): I can't stress this enough, but this method defeats the purpose of using Optional, as it reintroduces the risk of NoSuchElementException. Prefer safer alternatives like orElse(), orElseThrow(), or ifPresent().
Use ifPresentOrElse() for clear fallback logic: This method is particularly useful when you need to handle both the presence and absence of a value with different actions.
The following code get the name of a user using his id, if the user is not found we return null.
Old way of doing this :
public String getNameById(int id) {
User user = findUserById(id);
if(user == null) return null;
return user.getName();
}
Using Optional, we can see clearly from the method signature that the result might be absent. The code is more expressive, and the use of map() eliminates explicit null checks, making it more readable.
public Optional<String> getNameById(int id) {
return Optional.ofNullable(findUserById(id))
.map(User::getName);
}
The following code gets the company name from the user entity. It gets the adress then the company then the company name. If a null is found it returns “unknown”.
public String getCompanyName(User user) {
if (user != null) {
Address address = user.getAddress();
if (address != null) {
Company company = address.getCompany();
if (company != null) {
return company.getName();
}
}
}
return "Unknown";
}
Optional does a magnificent job in making this kind of use cases simple.
public String getCompanyName(User user) {
return Optional.ofNullable(user)
.map(User::getAddress)
.map(Address::getCompany)
.map(Company::getName)
.orElse("Unknown");
}
By using the Optional API we avoided using multiple if statments.
The Optional<T> class provides a powerful and expressive way to handle potential absence of values in Java. Its methods are designed to encourage a functional programming style, reducing the need for null checks and making your code cleaner and safer. With its rich API, you can handle optional values in multiple ways, each designed to fit specific use cases.
Understanding how to effectively use Optional can drastically improve the readability and reliability of your Java applications. Whether you're working with legacy code or developing new systems, integrating Optional in return types helps signal the possibility of missing values in a clear and type-safe way.