Optional.flatMap и Optional.map в Java: отличия с примерами

Пройдите тест, узнайте какой профессии подходите и получите бесплатную карьерную консультацию
В конце подарим скидку до 55% на обучение
Я предпочитаю
0%
Работать самостоятельно и не зависеть от других
Работать в команде и рассчитывать на помощь коллег
Организовывать и контролировать процесс работы

Быстрый ответ

Метод Optional.map позволяет преобразовать текущее значение с помощью переданной функции, после чего оборачивает получившийся результат в Optional.

Метод Optional.flatMap также преобразует значение, однако функция, которую он ожидает в качестве аргумента, должна возвращать Optional. Это позволяет избежать создания вложенных Optional.

Рассмотрим пример с map и функцией, не возвращающей Optional:

Java
Скопировать код
Optional<String> opt = Optional.of("test");

Optional<Integer> length = opt.map(String::length); // Optional[4]

Пример с flatMap и функцией, возвращающей Optional:

Java
Скопировать код
Optional<String> opt = Optional.of("test");

Optional<Integer> length = opt.flatMap(s -> Optional.of(s.length())); // Optional[4]

В случае с flatMap не происходит получения Optional<Optional<Integer>>, вместо этого мы получаем Optional<Integer>.

Пройдите тест и узнайте подходит ли вам сфера IT
Пройти тест

Выбор правильного метода

map для простой трансформации

Используйте map, чтобы применить функцию к значению в Optional и возвратить результат в новой Optional обертке:

Java
Скопировать код
Optional<String> text = Optional.of("1024");

Optional<Integer> number = text.map(Integer::valueOf); // Optional[1024]

flatMap для устранения вложенности

Если передаваемая в map функция возвращает Optional, то её следует заменить на flatMap для избежания создания вложенной структуры, что упростит код:

Java
Скопировать код
Optional<String> text = Optional.of("optional");

Optional<Optional<Integer>> badExample = text.map(s -> Optional.of(s.length())); // Неудачно: Optional[Optional[8]]

Optional<Integer> goodExample = text.flatMap(s -> Optional.of(s.length())); // Удачно: Optional[8]

flatMap эффективно сочетает в себе преобразование значения и устранение вложенности.

Выбирайте метод в зависимости от возвращаемого типа

Выбор между map и flatMap зависит от того, возвращает ли передаваемая функция Optional.

Избегайте NullPointerException

Перед вызовом get() на Optional, рекомендуется проверять наличие значения с помощью isPresent():

Java
Скопировать код
optionalValue.ifPresent(val -> System.out.println("Value: " + val));

Ответственное обращение с исключениями в методах

При использовании методов map и flatMap предусматривайте обработку возможных исключений, чтобы гарантировать корректное выполнение кода:

Java
Скопировать код
Optional<String> text = Optional.of("42");

Optional<Integer> number = text.flatMap(s -> {
    try {
        return Optional.of(Integer.parseInt(s));
    } catch (NumberFormatException e) {
        return Optional.empty();
    }
}); // Optional[42]

Визуализация

Предположим, нам нужно доставить другу подарок:

Markdown
Скопировать код
Optional.map:    [🎁] -> 🏠👉🏠 (Подарок оставлен у входа)
Optional.flatMap: [🎁] -> 🚛 -> 🏠 (Подарок доставлен аж до рук получателя)

Вывод: map прямо трансформирует содержащееся значение, тогда как flatMap позволяет контролировать процесс обработки данных.

Адаптация к различным сценариям

Последовательные операции

Для последовательного преобразования данных, в процессе которого каждый шаг может возвращать Optional, используйте цепочку flatMap:

Java
Скопировать код
Optional<String> result = optionalUser
    .flatMap(User::getAddress)
    .flatMap(Address::getCountry)
    .map(Country::getName);

Преобразование в Streams

Optional можно преобразовать в Stream для выполнения последующих операций:

Java
Скопировать код
Stream<String> stream = optionalString
    .map(Stream::of)
    .orElseGet(Stream::empty);

Теоретические основы в Java 8

Для более глубокого изучения теоретических основ обратите внимание на книгу "Java 8 In Action", где подробно описаны функциональные возможности Java 8.

Полезные материалы

  1. Optional (Java Platform SE 8 ) — официальная документация Java по Optional.flatMap.
  2. Optional (Java Platform SE 8 ) — руководство Oracle по Optional.map.
  3. Understanding map and flatMap — статья, разъясняющая различия и сходства между map и flatMap.
  4. Baeldung on Java Optional — руководство Baeldung по использованию Optional.
  5. DZone — обсуждение на DZone, ещё один взгляд на разницу между map() и flatMap().
  6. Обсуждение map против flatMap — ветка на Stack Overflow, посвящённая сравнению Optional.flatMap и Optional.map.