Java - Optional Class
Introduced in Java 8, Optional
Contents
Creating an Optional
Optional.of()NullPointerExceptionOptional.ofNullable()Optional.empty()Optional.empty()nullOptionalNullPointerException
// 1. Empty Optional — holds no value
Optional<String> empty = Optional.empty();
// 2. Non-null value — throws NullPointerException if value is null
Optional<String> present = Optional.of("hello");
// 3. Nullable value — wraps null in an empty Optional instead of throwing
Optional<String> nullable = Optional.ofNullable(null); // same as Optional.empty()
Optional<String> nullable2 = Optional.ofNullable("world"); // same as Optional.of("world")
Checking for a Value
isPresent()isEmpty()ifPresent()ifPresentOrElse()if
Optional<String> opt = Optional.of("Java");
opt.isPresent(); // true — value is present
opt.isEmpty(); // false — Java 11+
Optional<String> empty = Optional.empty();
empty.isPresent(); // false
empty.isEmpty(); // true
Retrieving the Value
get()NoSuchElementExceptionOptionalisPresent()orElse()orElseGet()SupplierorElseThrow()
Optional<String> opt = Optional.ofNullable(getValue()); // may be null
// get() — throws NoSuchElementException if empty; AVOID using directly
String s1 = opt.get();
// orElse() — return default value if empty (default always evaluated)
String s2 = opt.orElse("default");
// orElseGet() — return result of Supplier; lazy (only called if empty)
String s3 = opt.orElseGet(() -> computeDefault());
// orElseThrow() — throw custom exception if empty
String s4 = opt.orElseThrow(() -> new IllegalStateException("Value missing"));
// ifPresent() — execute consumer only if value present
opt.ifPresent(v -> System.out.println("Found: " + v));
// ifPresentOrElse() — Java 9+
opt.ifPresentOrElse(
v -> System.out.println("Found: " + v),
() -> System.out.println("Not found")
);
orElseGet()orElse()orElse()Transforming with map() and flatMap()
map()flatMap()Optional<Optional<T>>
Optional<String> name = Optional.of(" alice ");
// map — trim and uppercase
Optional<String> upper = name.map(String::trim).map(String::toUpperCase);
upper.ifPresent(System.out::println); // ALICE
// Without Optional (old style — prone to NPE):
String result = null;
String raw = getName();
if (raw != null) {
result = raw.trim().toUpperCase();
}
// flatMap — when the mapper returns Optional itself
class User {
Optional<Address> getAddress() { return Optional.ofNullable(address); }
}
class Address {
Optional<String> getCity() { return Optional.ofNullable(city); }
}
// flatMap avoids Optional<Optional<String>>
Optional<String> city = getUser()
.flatMap(User::getAddress)
.flatMap(Address::getCity);
Filtering with filter()
filter()
Optional<Integer> age = Optional.of(25);
Optional<Integer> adult = age.filter(a -> a >= 18);
adult.isPresent(); // true
Optional<Integer> minor = Optional.of(15).filter(a -> a >= 18);
minor.isPresent(); // false — 15 < 18 so filter returns empty
Practical Example
A service method that looks up a user by ID and returns the user's email in uppercase:
public Optional<String> findUserEmailById(int id) {
return userRepository.findById(id) // returns Optional<User>
.filter(User::isActive) // keep only active users
.map(User::getEmail) // Optional<String>
.map(String::toUpperCase); // transform email
}
// Caller:
String email = findUserEmailById(42)
.orElse("unknown@example.com");
Best Practices
- Do not use Optional as a field type: it is not
; use it only as method return types.Serializable - Do not use Optional as a method parameter: callers can still pass
; use method overloading instead.null - Avoid calling
without checking isPresent(): defeats the purpose; useget() /orElse .orElseGet - Do not use Optional for collections: return an empty collection instead of
.Optional<List> - Use for return values only: to signal that a result might be absent, replacing
return.null