Functional Programming & Streams
Optional
Optional<T> is a return type that makes "no result" impossible to ignore. Use it for possibly-absent return values; don't use it for fields, parameters, or collections — and never call bare get().- Purpose: API honesty — callers must consciously handle absence (EJ 55)
- Consume with
orElse,orElseGet(supplier),orElseThrow,ifPresent,map - Never
isPresent()+get()when a functional form exists - Don't wrap collections in Optional — return the empty collection
- Skip Optional for performance-critical returns and for fields (use null + discipline there)
Optional.stream()bridges into stream pipelines
Optional<User> found = repo.findByEmail(email);
User user = found.orElseThrow(() -> new NoSuchUserException(email));
String name = found.map(User::name).orElse("anonymous");
found.ifPresentOrElse(this::greet, this::showSignup);
// orElse vs orElseGet — the argument of orElse is ALWAYS evaluated:
config = stored.orElse(loadDefaults()); // loadDefaults runs even when present!
config = stored.orElseGet(this::loadDefaults); // lazy — usually what you meantChaining absorbs null-check pyramids: person.flatMap(Person::address).map(Address::city).filter(c -> !c.isBlank()). Each step runs only if a value is present. For interop, Optional.ofNullable(legacyCall()) enters the monad; opt.orElse(null) exits it at legacy boundaries.