Получить доступ

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

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

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

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

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

Так подсказку видит пользователь sotto на живом собеседовании — за пару секунд, пока вы думаете вслух.

Подробно

Замысел. Метод 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() без проверки
  • ✗Как поле класса и параметр метода повсюду
  • ✗Всегда вызывать get() сразу после создания
  • ✗Оборачивать в Optional любые коллекции

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

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

Разбор темы

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

Закрытая бета

Подсказки на собеседовании — в реальном времени

sotto слышит вопрос интервьюера и показывает короткий ответ и план, как в блоке «Коротко». Оставьте контакт — пришлём доступ и промокод.

  • Промокод на 2 часа — сверх пробных 30 минут
  • Программа для Windows — скачать сразу, войти — через Яндекс ID или VK ID
  • Прямая связь с разработчиком: что улучшить — сделаем