Optional
Use Optional<T> to represent a value that may or may not be present, eliminating null checks and NullPointerExceptions.
Overview
Key Points
- •Optional.of(value) creates an Optional with a non-null value
- •Optional.ofNullable(value) creates an Optional from a value that might be null
- •Optional.empty() creates an empty Optional
- •isPresent() and isEmpty() check presence
- •get() retrieves the value but throws if empty. Prefer orElse or ifPresent
- •orElse(default) returns the value or a default
- •orElseGet(supplier) returns the value or computes a default lazily
- •ifPresent(consumer) runs the consumer only if a value is present
- •map, filter, flatMap work on Optional like on streams
Examples
Creating and using Optional
import java.util.Optional;
public class Main {
static Optional<String> findUser(int id) {
if (id == 1) return Optional.of("Alice");
if (id == 2) return Optional.of("Bob");
return Optional.empty();
}
public static void main(String[] args) {
Optional<String> user1 = findUser(1);
Optional<String> missing = findUser(99);
// Safe patterns
user1.ifPresent(name -> System.out.println("Found: " + name)); // Found: Alice
String name = missing.orElse("Unknown");
System.out.println(name); // Unknown
// Compute default only when needed (lazy)
String computed = missing.orElseGet(() -> "Default-" + System.currentTimeMillis());
System.out.println(computed);
// orElseThrow
try {
missing.orElseThrow(() -> new RuntimeException("User not found"));
} catch (RuntimeException e) {
System.out.println(e.getMessage());
}
}
}orElseGet takes a Supplier (lazy). orElse evaluates the argument eagerly even if the Optional is present. Use orElseGet when the default computation is expensive.
Chaining Optional with map and filter
import java.util.Optional;
public class Main {
static Optional<String> getUsername(int userId) {
if (userId == 42) return Optional.of("alice_wonder");
return Optional.empty();
}
public static void main(String[] args) {
// map transforms the value if present
Optional<String> upper = getUsername(42)
.map(String::toUpperCase);
System.out.println(upper.orElse("no user")); // ALICE_WONDER
// filter retains the value only if condition holds
Optional<String> longName = getUsername(42)
.filter(s -> s.length() > 5);
System.out.println(longName.isPresent()); // true
// Chaining: get username, check it is not "admin"
getUsername(42)
.filter(name -> !name.equals("admin"))
.map(name -> "Welcome, " + name + "!")
.ifPresent(System.out::println); // Welcome, alice_wonder!
// Empty chain
getUsername(99)
.map(String::toUpperCase)
.ifPresent(System.out::println); // nothing printed
}
}map and filter on Optional propagate emptiness. If the Optional is empty, the chain short-circuits and the result is empty.
Optional with streams
import java.util.List;
import java.util.Optional;
public class Main {
public static void main(String[] args) {
List<Integer> nums = List.of(3, 7, 2, 9, 4, 6, 1);
// findFirst returns Optional
Optional<Integer> firstEven = nums.stream()
.filter(n -> n % 2 == 0)
.findFirst();
firstEven.ifPresent(n -> System.out.println("First even: " + n)); // 2
// max returns Optional
nums.stream()
.max(Integer::compareTo)
.ifPresent(m -> System.out.println("Max: " + m)); // 9
// Stream of optionals
List<Optional<String>> optionals = List.of(
Optional.of("Alice"), Optional.empty(), Optional.of("Bob")
);
optionals.stream()
.filter(Optional::isPresent)
.map(Optional::get)
.forEach(System.out::println); // Alice
Bob
}
}Stream terminal operations like findFirst, findAny, min, max, reduce return Optional to force callers to handle the empty case.
Common Mistakes
- Calling get() on an Optional without checking isPresent(). This throws NoSuchElementException. Use orElse, orElseGet, or ifPresent instead
- Using Optional as a method parameter: Optional<String> name is an antipattern. Accept String directly and let callers pass null (or better, use overloading)
- Using Optional.of(null): this throws NullPointerException. Use Optional.ofNullable(value) when the value might be null
Note
The most common Optional idiom in production is: return Optional.ofNullable(result) at the end of a search method, and optional.orElseThrow(ExceptionType::new) at the call site when absence is an error.
Exercises
Write Java code and click Run to execute it instantly. When your output looks correct, mark as done.
Completed: 0 / 4 exercises
Knowledge Check
Question 1 of 4