Skip to main content

Command Palette

Search for a command to run...

Deep dive into the optional java API

Published
5 min read
Deep dive into the optional java API
M

Moroccan software developer, Java/Spring. Love to learn, eager to write.

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.

What is optional ?

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.

Methods in 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:

  1. Static Factory Methods

  • empty():

    Returns an empty Optional instance.

      Optional<String> emptyOptional = Optional.empty();
    
  • of(T value):

    Returns an Optional with the specified non-null value.

      Optional<String> opt = Optional.of("value");
    
  • ofNullable(T value):

    Returns an Optional describing the specified value, or an empty Optional if the value is null.

      Optional<String> opt = Optional.ofNullable(null);
    
  1. Basic Methods for Value Handling

  • get():

    If a value is present, returns the value. Otherwise, throws NoSuchElementException.

  • isPresent():

    Returns true if the value is present, otherwise false.

  • isEmpty() (Java 11):

    Returns true if the Optional is empty, otherwise false.

  1. Value Retrieval with Default Handling

  • orElse(T other):

    Returns the value if present, otherwise returns other.

  • orElseGet(Supplier<? extends T> other):

    Returns the value if present, otherwise calls the Supplier and 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.

  1. Conditional Execution Methods

  • 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.

  1. Mapping Methods

  • map(Function<? super T, ? extends U> mapper):

    If a value is present, applies the provided mapping function to it and returns a new Optional with the result.

  • flatMap(Function<? super T, Optional<U>> mapper):

    Similar to map(), but the mapper function must return an Optional.

  • filter(Predicate<? super T> predicate):

    If a value is present and it matches the given predicate, returns an Optional describing the value; otherwise, returns an empty Optional.

  1. Stream and Iteration

  • stream() (Java 9):

    If a value is present, returns a Stream containing the value; otherwise, returns an empty Stream.

Best Practices for Using Optional

  • Avoid 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.

Clean code example with Optional

  1. No null check

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);
}
  1. Chain methods not ifs

    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.

Conclusion

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.

More from this blog

Loukmane's articles

9 posts

Software Developer @MyTower. Crafting clean code by day, iced coffee addict by choice. Casual gamer and chess enjoyer ♟️💻☕. Always learning, always coding.