Transforming Optional

map, flatMap, filter, or

Optional has its own small pipeline. If the Optional is empty, each step is skipped and the result stays empty — no null checks needed.

  • map(fn): transform the value.
  • flatMap(fn): when fn itself returns an Optional (avoids Optional<Optional<T>>).
  • filter(pred): keep the value only if it matches.
  • or(supplier) (Java 9): fall back to another Optional.
  • stream() (Java 9): 0 or 1 element stream, handy with flatMap.

Chained Lookup

Example

User → address → pincode, where each step may be missing.

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Map<String, User> db = Map.of(
                "u1", new User("Ravi", Optional.of(new Address("Pune", "411001"))),
                "u2", new User("Meena", Optional.empty()));

        for (String id : List.of("u1", "u2", "u3")) {
            String pin = Optional.ofNullable(db.get(id))
                    .flatMap(User::address)
                    .map(Address::pincode)
                    .filter(p -> p.startsWith("4"))
                    .orElse("not available");
            System.out.println(id + " -> " + pin);
        }

        Optional<String> fromCache = Optional.empty();
        String value = fromCache.or(() -> Optional.of("from-database")).get();
        System.out.println(value);

        List<Optional<String>> maybeEmails = List.of(Optional.of("[email protected]"), Optional.empty(), Optional.of("[email protected]"));
        System.out.println(maybeEmails.stream().flatMap(Optional::stream).toList());
    }
}

record Address(String city, String pincode) {}
record User(String name, Optional<Address> address) {}

Output

u1 -> 411001
u2 -> not available
u3 -> not available
from-database
[[email protected], [email protected]]