Script Valley
Java: Complete Language Course
Modern Java Features and Best PracticesLesson 6.2

Java Optional - avoiding NullPointerException properly

Optional creation, of, ofNullable, empty, isPresent, get, orElse, orElseGet, map, flatMap, filter, ifPresent, Optional anti-patterns, return type usage

Optional

Optional<T> is a container that explicitly signals a value may or may not be present. It forces callers to handle the absent case at compile time, unlike null which fails silently at runtime.

Creating Optional

Optional present  = Optional.of("hello");      // throws NullPointerException if null
Optional nullable = Optional.ofNullable(null); // safe with null input
Optional empty    = Optional.empty();

Consuming Optional

Optional name = findUser(42).map(User::getName);

// Unsafe - throws NoSuchElementException if empty
String bad = name.get();

// Safe alternatives
String safe     = name.orElse("Anonymous");
String computed = name.orElseGet(() -> generateDefault());
String thrown   = name.orElseThrow(() -> new UserNotFoundException(42));

// Chain transformations without unwrapping
name.filter(n -> n.length() > 3)
    .map(String::toUpperCase)
    .ifPresent(System.out::println);

flatMap - Nested Optional

Optional city = findUser(42)
    .flatMap(user -> user.getAddress())
    .map(Address::getCity); // avoids Optional>

Anti-patterns: Do not use Optional as a field type - poor serialization support. Do not use it as a method parameter - it clutters call sites and forces callers to wrap values. Do not wrap every return type defensively either; it adds allocation overhead and makes the API noisier. Reserve Optional for methods where absence is a meaningful, expected outcome: lookup by key, finding the first matching element, or reading an optional configuration value.

Up next

Java records for immutable data classes

Sign in to track progress