Optional basics

Core Java · lesson 15 of 42 · 3 min read

Model a possibly-missing value in the type system instead of returning null.

Open this lesson in the learning hub

Key points

  • Optional<T> is a small box holding a value or nothing. It makes "may be absent" part of the signature.
  • Create with Optional.of(x) (never null), Optional.ofNullable(x) (may be null) or Optional.empty().
  • Transform with map, filter and flatMap — the chain simply stops when the value is missing.
  • Unwrap with orElse, orElseGet or orElseThrow. Only orElseGet defers its fallback until it is needed.
  • Avoid get() and isPresent() ladders. That is a null check with extra ceremony.
  • Use it as a return type. Do not use it for fields, parameters, or elements inside a collection.

Example

import java.util.List;
import java.util.Optional;

public class Main {

    record User(String name, String email) {}

    static Optional<User> findUser(List<User> users, String name) {
        return users.stream().filter(u -> u.name().equals(name)).findFirst();
    }

    public static void main(String[] args) {
        List<User> users = List.of(new User("Ada", "ada@example.com"), new User("Linus", null));

        System.out.println("found:   " + findUser(users, "Ada").map(User::email).orElse("no email"));
        System.out.println("missing: " + findUser(users, "Ghost").map(User::email).orElse("no email"));

        Optional<String> email = Optional.ofNullable(users.get(1).email());
        System.out.println("isPresent: " + email.isPresent() + " -> " + email.orElseGet(() -> "generated@example.com"));

        findUser(users, "Ada").ifPresentOrElse(
                u -> System.out.println("ifPresentOrElse: hello " + u.name()),
                () -> System.out.println("ifPresentOrElse: nobody"));

        System.out.println("chained: " + Optional.of("  trim me  ")
                .map(String::strip)
                .filter(s -> !s.isEmpty())
                .orElse("(blank)"));

        try {
            findUser(users, "Ghost").orElseThrow(() -> new IllegalStateException("no such user"));
        } catch (IllegalStateException e) {
            System.out.println("orElseThrow: " + e.getMessage());
        }
    }
}

Return Optional so callers cannot forget the value might be missing.

This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the Core Java course, and every lesson in it is listed on the Core Java contents page.