Вопрос с собеседования · Java

Как правильно использовать Optional?

MiddleЛямбды и Stream API
Ещё спрашивают так:
  • Для чего задумывался Optional и какие есть антипаттерны его использования?
  • Для чего задумывался Optional, чем orElse отличается от orElseGet и какие есть антипаттерны его использования?
Коротко

Optional — тип возвращаемого значения «результата может не быть», видимый в сигнатуре. Распаковывают через map, flatMap, filter, orElseGet, orElseThrow, а не isPresent() + get(). Не для полей, параметров и коллекций.

  • orElse вычисляет аргумент всегда, orElseGet — лениво
  • Optional<List> не нужен — верните пустой список
  • Для примитивов — OptionalInt, OptionalLong

А ещё Optional не сериализуем — ещё одна причина не делать его полем

Подробно

Замысел. Метод findById возвращает Optional<User> — вызывающий видит в сигнатуре, что пользователя может не быть, и не забудет обработать этот случай.

Идиоматичное использование:

String city = repo.findById(id)
    .map(User::address)
    .map(Address::city)
    .orElse("неизвестно");

User u = repo.findById(id)
    .orElseThrow(() -> new NotFoundException(id));

repo.findById(id).ifPresentOrElse(this::notify, this::log);

Антипаттерны:

  • if (opt.isPresent()) opt.get() — тот же null-check, только длиннее;
  • голый get() — NoSuchElementException вместо NPE (с Java 10 есть честное имя orElseThrow());
  • Optional как поле — не сериализуем, лишний объект на экземпляр;
  • Optional как параметр — вызывающий всё равно должен создать Optional, проще перегрузка или null-допускающий параметр;
  • Optional<List<T>> — пустая коллекция уже означает «ничего нет»;
  • orElse(expensive()) — дорогое значение вычисляется всегда.

Что хотят услышать

  • Назначение: возвращаемое значение.
  • Идиоматичные методы.
  • Антипаттерны.

Частые ошибки

  • isPresent + get.
  • Optional в полях JPA-сущностей.

Проверьте себя

Один верный вариант. Подумайте, потом откройте ответ.

Показать варианты и ответ
  • ✓Как тип результата; распаковывать через map/orElseGet/orElseThrow, а не get()
  • ✗Как тип полей и параметров везде, где значение может быть null
  • ✗Всегда вызывать get() сразу после создания
  • ✗Оборачивать в Optional любые коллекции

Что спросят дальше

  • Чем orElse отличается от orElseGet?
  • Почему Optional не заменяет валидацию входных параметров?
  • Почему Optional не реализует Serializable?
  • Стоит ли возвращать Optional из метода репозитория?

Разбор темы

Связанные вопросы

Партнёр платформы

Разбор собеседования с sotto

После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.

Разбор собеседования