Java 27: Optional — Avoiding Null
easy⏱ 5 mincoursejava
Create + unwrap
Optional.of(x) (x must be non-null), Optional.ofNullable(x) (x may be null), Optional.empty(). To unwrap: .orElse(default), .orElseGet(() -> compute()) (lazy), .orElseThrow(), .orElseThrow(() -> new MyExc()). .get() throws on empty — avoid.
Chain with map + flatMap
user.getAddress().map(Address::getCity).orElse("unknown") — if any step is empty, the chain short-circuits. flatMap is for when your mapper itself returns an Optional: user.getSpouse().flatMap(User::getEmail).
Optional<String> city = userRepo.findById(id)
.map(User::getAddress) // Optional<Optional<Address>>... wait
.flatMap(a -> a.map(Address::getCity)); // use flatMap for Optional-returning mappers
Anti-patterns
(1) Optional fields — not their design intent, use null + validation. (2) Optional method parameters — forces callers to wrap, use overloads instead. (3) Optional<List<T>> — return empty list instead. (4) .isPresent() + .get() — use .orElse or .ifPresent. (5) Serializing Optional — it's not Serializable.
Build an Optional chain
Implement Opt<T> with of, empty, map, flatMap, orElse, ifPresent, filter. Chain: find user → get address → get postal code → default to 'UNKNOWN'. Test with present and absent paths.
orElseGet for expensive defaults
.orElse(computeDefault()) always evaluates computeDefault() — even when the value is present. .orElseGet(() -> computeDefault()) is lazy — only called on empty. Use orElseGet for any default that's more than a constant.
Quiz: When Optional fields are OK
Never on an entity or DTO. When is an Optional field OK? Basically never. Use @Nullable + null for fields; reserve Optional for return values where the caller needs to handle absence. Jackson and JPA both have trouble with Optional fields.