# Deep dive into the optional java API

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.

```java
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()`.

```java
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.
    
    ```java
    Optional<String> emptyOptional = Optional.empty();
    ```
    
* `of(T value)`:
    
    > Returns an `Optional` with the specified non-null value.
    
    ```java
    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`.
    
    ```java
    Optional<String> opt = Optional.ofNullable(null);
    ```
    

2. ### 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`.
    

3. ### 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`.
    

4. ### 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`.
    

5. ### 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`.
    

6. ### 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.
    
* **<mark>Do not use</mark>** `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 :

```java
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.

```java
public Optional<String> getNameById(int id) {
    return Optional.ofNullable(findUserById(id))
                   .map(User::getName);
}
```

2. ### 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”*.
    

```java
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.

```java
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.
