Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Optional

A search method does not always find something. If it returns null in that case, the calling code can easily forget the check and crash with a NullPointerException. Optional is a container that either holds a value or is empty, and the type itself reminds you: "there may be no result".

Creating an Optional

Optional.of() wraps an existing value, Optional.empty() creates an empty container. The isPresent() and isEmpty() methods check whether there is a value inside:

void main() {
    Optional<String> name = Optional.of("Anna");
    Optional<String> nothing = Optional.empty();
 
    IO.println(name.isPresent());
    IO.println(nothing.isEmpty());
    IO.println(name);
    IO.println(nothing);
}

Output:

true
true
Optional[Anna]
Optional.empty

A method that may not find anything

The main use of Optional is as the return type of a search method. If a value may turn out to be null, it is wrapped with Optional.ofNullable():

Map<String, String> phones = Map.of("Anna", "+49 30 1234567");
 
Optional<String> findPhone(String name) {
    return Optional.ofNullable(phones.get(name));
}
 
void main() {
    IO.println(findPhone("Anna"));
    IO.println(findPhone("Oleg"));
}

Output:

Optional[+49 30 1234567]
Optional.empty

Whoever calls findPhone() sees from the type that there may be no phone and has to decide what to do in that case.

A default value

orElse() returns the value from the container or a fallback if the container is empty. orElseGet() does the same but computes the fallback with a lambda — only when it is actually needed:

void main() {
    Optional<String> city = Optional.empty();
    IO.println(city.orElse("City not specified"));
    IO.println(city.orElseGet(() -> "Berlin"));
}

Output:

City not specified
Berlin

Transforming: map and filter

map() applies a function to the value if there is one and returns a new Optional. filter() keeps the value only if it matches a condition. An empty Optional passes through them unchanged:

void main() {
    Optional<String> email = Optional.of("  Anna@Mail.com ");
 
    String result = email
            .map(String::strip)
            .map(String::toLowerCase)
            .filter(e -> e.contains("@"))
            .orElse("no address");
    IO.println(result);
}

Output:

anna@mail.com

An action if the value is present

ifPresent() runs an action only when there is a value, and ifPresentOrElse() also lets you describe a fallback branch. orElseThrow() returns the value or throws an exception if there is none:

void main() {
    Optional<Integer> discount = Optional.of(10);
    discount.ifPresent(d -> IO.println("Discount " + d + "%"));
 
    Optional<Integer> none = Optional.empty();
    none.ifPresentOrElse(
            d -> IO.println("Discount " + d + "%"),
            () -> IO.println("No discount"));
}

Output:

Discount 10%
No discount

Common mistake

The get() method returns the value, but on an empty Optional it throws an exception. Calling it without a check is the same mistake as dereferencing null:

void main() {
    Optional<String> phone = Optional.empty();
    IO.println(phone.get());
}

Output:

Exception in thread "main" java.util.NoSuchElementException: No value present

Instead of get(), use orElse(), ifPresent() or orElseThrow() with a clear message. And do not use Optional for fields and parameters — it is designed as a method's return type.

Thanks for reading!

Donate to the site — we work hard for you.