Optional Best Practices

Do and Do Not

DoDo not
Return Optional from methods that may find nothing (findById)Use Optional for fields, method parameters or in collections
Use map/orElse/orElseThrowCall get() without checking — that is just a null check in disguise
Return an empty list instead of Optional<List>Return null from a method whose return type is Optional
Use OptionalInt/OptionalDouble for primitivesUse Optional in serialized DTOs / JPA entities

Spring Data Style

Spring Data repositories return Optional from findById. The usual service pattern is orElseThrow with a domain exception, which a @ControllerAdvice turns into HTTP 404.

public ProductDto getProduct(Long id) {
    return productRepository.findById(id)
            .map(ProductDto::from)
            .orElseThrow(() -> new ProductNotFoundException(id));
}

Practice

Exercise: Write a method Optional<Integer> parseAge(String s) that returns empty when s is not a number or is negative.

Show answer
static Optional<Integer> parseAge(String s) {
    try {
        return Optional.of(Integer.parseInt(s.trim())).filter(a -> a >= 0);
    } catch (NumberFormatException e) {
        return Optional.empty();
    }
}