Optional часто используют как “защиту от null”, но если применять его везде подряд, код может стать сложнее, а не безопаснее.
Например, плохая практика - хранить Optional в поле класса:
public class User {
private Optional<String> email;
}
На первый взгляд кажется удобно: email может быть, а может не быть.
Но Optional задумывался в первую очередь как возвращаемое значение метода, а не как тип поля.
Лучше хранить само значение:
public class User {
private String email;
}
А Optional возвращать из метода, где отсутствие результата является нормальным сценарием:
public Optional<String> getEmail() {
return Optional.ofNullable(email);
}
Ещё один частый антипример принимать Optional как параметр метода:
public void updateEmail(Optional<String> email) {
}
Такой код усложняет вызовы и заставляет вызывающий код оборачивать значение вручную.
Обычно понятнее сделать перегрузку метода или принять обычное nullable-значение с явной проверкой:
public void updateEmail(String email) {
if (email == null || email.isBlank()) {
throw new IllegalArgumentException("Email is blank");
}
this.email = email;
}
Также опасно вызывать get() без проверки:
User user = findUser(id).get();
Если пользователя нет, код упадёт с NoSuchElementException.
Безопаснее обработать отсутствие явно:
User user = findUser(id)
.orElseThrow(() -> new UserNotFoundException(id));
Или задать fallback:
String name = user.getName()
.orElse("Guest");
Optional хорошо подходит там, где метод может ничего не найти:
public Optional<User> findUser(Long id) {
return userRepository.findById(id);
}
Но если значение обязательно по бизнес-логике, лучше не прятать ошибку в Optional, а валидировать данные раньше.
👉 Java Ready | #практика