Optional in Java serves as a container that may or may not contain a non-null value, providing a safer alternative to direct null references.
// Creating Optional instances
User validUser = new User("admin", 1);
User nullUser = null;
// Wrapping non-null value
Optional<User> presentOptional = Optional.of(validUser);
// Wrapping potentially null value (most common usage)
Optional<User> nullableOptional = Optional.ofNullable(nullUser);
// Empty Optional
Optional<User> emptyOptional = Optional.empty();
// Value retrieval and processing
// Execute only if value exists
presentOptional.ifPresent(u -> System.out.println("Username: " + u.getName())); // Output: Username: admin
nullableOptional.ifPresent(u -> System.out.println("Username: " + u.getName())); // No output
// Default value when empty
User fallbackUser = nullableOptional.orElse(new User("default", 0));
System.out.println(fallbackUser.getName()); // Output: default
// Lazy default value generation
User lazyDefault = nullableOptional.orElseGet(() -> generateDefaultUser());
System.out.println(lazyDefault.getName()); // Output: default_lazy
// Throw exception when empty
try {
nullableOptional.orElseThrow(() -> new IllegalArgumentException("User not found"));
} catch (IllegalArgumentException e) {
System.out.println(e.getMessage()); // Output: User not found
}
Chained operations with Optional allow fluent navigation through object hierarchies while maintaining null safety:
Optional.ofNullable(user)
.map(User::getAddress)
.map(Address::getCity)
.ifPresent(System.out::println);
The map operasion transforms values while filter selectively processes elements based on predicates.