Returning an Optional
OCP Exam Topic — Use
Optional<T>to represent values that may or may not be present and avoidNullPointerException. Covered in Chapter 8 of OCP Java SE 21 Developer Study Guide (Selikoff & Boyarsky).
What Is Optional?
Optional<T> (in java.util) is a container object that either holds a non-null value or is empty. It makes the possibility of "no value" explicit in a method's return type, encouraging callers to handle the absent case rather than assuming a result is always present.
javaimport java.util.Optional;
// returns empty when not found — caller must handle it
public Optional<String> findUsername(int id) {
if (id == 1) return Optional.of("alice");
return Optional.empty();
}Creating an Optional
| Factory Method | Description |
|---|---|
Optional.of(value) |
Creates an Optional with the given non-null value; throws NullPointerException if value is null |
Optional.ofNullable(value) |
Creates an Optional with the value if non-null, or empty if null |
Optional.empty() |
Creates an empty Optional |
javaOptional<String> present = Optional.of("Java");
Optional<String> nullable = Optional.ofNullable(null); // empty
Optional<String> empty = Optional.empty();
// Optional.of(null) throws NullPointerException immediatelyChecking Presence
| Method | Description |
|---|---|
isPresent() |
Returns true if a value is present |
isEmpty() |
Returns true if no value is present (Java 11+) |
javaOptional<String> opt = Optional.of("Hello");
if (opt.isPresent()) {
System.out.println(opt.get()); // Hello
}Retrieving the Value
| Method | Description |
|---|---|
get() |
Returns the value; throws NoSuchElementException if empty |
orElse(other) |
Returns the value if present, otherwise returns other |
orElseGet(supplier) |
Returns the value if present, otherwise calls supplier.get() |
orElseThrow() |
Returns the value or throws NoSuchElementException |
orElseThrow(exceptionSupplier) |
Returns the value or throws the supplied exception |
javaOptional<String> name = Optional.empty();
String result1 = name.orElse("Unknown"); // "Unknown"
String result2 = name.orElseGet(() -> "Generated"); // "Generated"
// name.get(); // throws NoSuchElementException — avoid calling get() without checkingjavaOptional<String> name = Optional.of("Alice");
String upper = name.orElseThrow(); // "Alice" — safe because value is presentPrefer orElse / orElseGet over get() — calling get() without first checking isPresent() defeats the purpose of Optional.
Executing Code When Value Is Present
| Method | Description |
|---|---|
ifPresent(consumer) |
Calls the consumer if value is present; does nothing if empty |
ifPresentOrElse(consumer, runnable) |
Calls consumer if present, runs runnable if empty (Java 9+) |
javaOptional<String> opt = Optional.of("OCP");
opt.ifPresent(s -> System.out.println("Found: " + s)); // Found: OCP
Optional.empty().ifPresentOrElse(
s -> System.out.println("Found: " + s),
() -> System.out.println("Nothing found") // Nothing found
);Transforming an Optional
These methods apply a function to the contained value and return a new Optional.
| Method | Description |
|---|---|
map(function) |
Transforms the value if present; returns empty if the Optional is empty or the function returns null |
filter(predicate) |
Returns the Optional unchanged if the predicate passes; returns empty otherwise |
flatMap(function) |
Like map, but the function returns an Optional (avoids nested Optional<Optional<T>>) |
javaOptional<String> opt = Optional.of(" hello ");
Optional<String> trimmed = opt.map(String::strip); // Optional["hello"]
Optional<String> upper = opt.map(String::strip).map(String::toUpperCase); // Optional["HELLO"]
Optional<String> filtered = opt.map(String::strip)
.filter(s -> s.length() > 3); // Optional["hello"]
Optional<String> empty = opt.filter(s -> s.isBlank()); // Optional.emptyflatMap example:
javaOptional<String> findCity(String code) {
return code.equals("NY") ? Optional.of("New York") : Optional.empty();
}
Optional<String> code = Optional.of("NY");
Optional<String> city = code.flatMap(this::findCity); // Optional["New York"]Optional and Streams
Optional integrates with the Stream API. Optional.stream() (Java 9+) returns a stream of zero or one element:
javaOptional<String> opt = Optional.of("Java");
opt.stream().forEach(System.out::println); // JavaThis is useful when combining Optionals with Stream.flatMap.
Key Points to Remember
Optional.of(value)— non-null value required; throws NPE for null.Optional.ofNullable(value)— safe for null; returns empty Optional if null.Optional.empty()— creates an empty Optional.- Avoid calling
get()without first verifyingisPresent()— useorElse,orElseGet, ororElseThrowinstead. ifPresentexecutes aConsumeronly when a value is present.maptransforms the value;filterconditionally keeps it;flatMapis used when the mapping function itself returns an Optional.- Optional is intended as a method return type, not as a field type or method parameter type.