Definition
- map(Function): transforms if present, returns empty if absent. Enables chaining.
- flatMap(Function): when the function returns Optional, avoids
Optional.> - filter(Predicate): keeps value if predicate matches, returns empty otherwise.
- orElse/orElseGet: provides default value (eager/lazy).
- orElseThrow: fails fast with meaningful exception.
- ifPresent/ifPresentOrElse: executes action(s) conditionally.
- Anti-pattern:
if (opt.isPresent()) { opt.get() }is a glorified null check.
isPresent()+get() is like opening the sealed envelope from National Bank of India with bare hands: you might cut yourself (NoSuchElementException). The idiomatic API gives proper tools: orElse is 'if empty, use this default.' map is 'if there is a cheque, convert to rupees.' filter is 'if the cheque is above Rs.10,000, keep it.' flatMap is 'if the envelope contains another envelope, open both.'
Understanding the Concepts
What is idiomatic Optional usage?
Never use isPresent()+get(). Use the functional API: map, flatMap, filter, orElse, orElseThrow, ifPresent.
How do you use map for transformations?
package com.bank.service;
import java.math.BigDecimal;
import java.util.Optional;
public class IdiomaticOptional {
record Account(String id, String holder, BigDecimal balance, boolean active) {
Optional<String> getMiddleName() { return Optional.empty(); }
}
static Optional<Account> findAccount(String id) {
if ("SAV2001".equals(id)) {
return Optional.of(new Account("SAV2001", "Rajesh", new BigDecimal("125000"), true));
}
return Optional.empty();
}
public static void main(String[] args) {
// map: transform if present, empty if absent
String name = findAccount("SAV2001")
.map(Account::holder)
.map(String::toUpperCase)
.orElse("UNKNOWN");
System.out.println("Name: " + name); // RAJESH
}
}
How do you use filter for conditions?
// filter: keep only if active
BigDecimal balance = findAccount("SAV2001")
.filter(Account::active)
.map(Account::balance)
.orElse(BigDecimal.ZERO);
System.out.println("Active balance: Rs." + balance); // Rs.125000
How do you use flatMap to avoid nested Optionals?
// flatMap: avoid nested Optional<Optional<T>>
String middle = findAccount("SAV2001")
.flatMap(Account::getMiddleName) // returns Optional, flatMap unwraps
.orElse("N/A");
System.out.println("Middle name: " + middle); // N/A
// Without flatMap: map would produce Optional<Optional<String>>
// Optional<Optional<String>> nested = findAccount("SAV2001").map(Account::getMiddleName);
// flatMap flattens it to Optional<String>
How do you use ifPresent and ifPresentOrElse?
// ifPresent: action only when present
findAccount("SAV2001")
.ifPresent(a -> System.out.println("Found: " + a.holder()));
// ifPresentOrElse (Java 9): handle both cases
findAccount("SAV9999")
.ifPresentOrElse(
a -> System.out.println("Found: " + a.holder()),
() -> System.out.println("Account not found")
);
How do you use orElse, orElseGet, and orElseThrow?
// orElse: cheap default (eager)
String name = findAccount("SAV9999")
.map(Account::holder)
.orElse("Unknown");
// orElseGet: expensive default (lazy)
Account account = findAccount("SAV9999")
.orElseGet(() -> repository.loadFromBackup("SAV9999"));
// orElseThrow: required value
Account account = findAccount("SAV9999")
.orElseThrow(() -> new AccountNotFoundException("SAV9999"));
How do you chain a complete pipeline?
// Complete null-safe pipeline: zero null checks
String result = findAccount(accountId)
.filter(Account::active)
.flatMap(Account::getMiddleName)
.map(String::toUpperCase)
.orElse("N/A");
What is the anti-pattern comparison?
| Anti-pattern | Idiomatic |
|-------------|----------|
| `if (opt.isPresent()) opt.get()` | `opt.ifPresent(action)` |
| `opt.isPresent() ? opt.get().name() : "default"` | `opt.map(T::name).orElse("default")` |
| `opt.isPresent() ? opt.get() : computeDefault()` | `opt.orElseGet(() -> computeDefault())` |
| `if (!opt.isPresent()) throw new Ex()` | `opt.orElseThrow(() -> new Ex())` |What should a senior engineer know?
- flatMap is needed when the mapping function itself returns Optional. map wraps the result in Optional (producing nested Optional
>). flatMap returns the result directly. - This parallels Stream.flatMap exactly.
- Optional.stream() (Java 9) bridges Optional and Stream:
optionals.stream().flatMap(Optional::stream)removes empties. - In code reviews, flag any isPresent()+get() as a code smell.
Visual Overview
Idiomatic chain:
────────────────
findAccount(id) Optional<Account>
│
.filter(Account::active) Optional<Account> (empty if inactive)
│
.flatMap(Account::getMiddle) Optional<String> (unwraps nested)
│
.map(String::toUpperCase) Optional<String>
│
.orElse("N/A") String (always a value)
Zero null checks. Zero isPresent(). Zero get().
Key Takeaway
The idiomatic way to use Optional is through its functional API: map for transformations, flatMap for nested Optionals, filter for conditions, orElse for defaults, orElseThrow for required values, and ifPresent for actions. Never use isPresent()+get().
flatMap is needed when the mapping function returns Optional. Without flatMap, map produces nested Optional
Remember one sentence: chain map, filter, flatMap, and orElse for null-safe pipelines, and never use isPresent()+get().
---