TL; DR Всякий раз, когда ваш груз находится внутри корабля, перевозимого другим кораблем - нанесите на карту этот корабль!

Программирование часто связано с преобразованием данных из одного типа в другой. Vavr предоставляет метод map, который вызывается во время так называемого счастливого пути: вы сопоставляете успех Try, значение Option, право Either, успешный результат Future и, наконец, элемент List.

Каждый раз, когда вы вводите map, ваша среда IDE предоставляет вам список предложений, и обычно среди них присутствует метод flatMap. Если вам интересно, когда и как использовать эту загадочную вещь, вот несколько примеров.

1) flatMap тот список списков

В этом примере flatMap используется для первого map каждого элемента listOfLists List, называемого innerList, другому List. Каждый innerList элемент, List из Strings остается нетронутым - это то, что означает x -> x. Другой способ вернуть ввод функции в map операции - использовать java.util.function.Function.identity().
Вторая задача flatMap - сгладить результат. В случае List из List это означает возврат одного List с элементами из всех внутренних List: [[a, b], [c, d], [e, f, g]] становится [a, b, c, d, e, f, g].

Немного более сложная версия этого примера - применить функцию карты к каждому внутреннему элементу List, например toLowerCase().

Подводя итог: flatMap на List из Lists применяет map функцию к каждому элементу внешнего List и возвращает один List.

2) flatMap, список опций

Точно так же flatMap может сгладить List из Option из String, чтобы вернуть List из String. Здесь хорошо то, что обрабатывается (отображается) только успех - в случае Option успех - это когда он определен.

Очевидно, мы также можем применить функцию map к каждому элементу, заключенному в Option. Вот метод toLowerCase():

Подводя итог: flatMap на List из Options применяет map функцию к каждому определенному Option и возвращает по одному List из каждого обернутого элемента.

3) flatMap, список попыток

Последний базовый пример, и мы готовы перейти к более интересным вещам. Сначала отображается List из Try объектов, каждый из которых завершает неудачу или успех (значение String). Короче говоря, Function.identity() оставляет успехи и отфильтровывает любые неудачи, оставляя нам List успешных Try объектов. Наконец, этот список сглаживается, что означает извлечь успешные значения из объектов Try и вернуть их как List.

Подводя итог: flatMap, примененный к List из Tries, запускает map функцию для каждого Try.Success и возвращает List каждого обернутого элемента.

Это очень простые примеры выполнения тривиальных операций с картой. Они просто сглаживают коллекцию коллекций, возвращая одну единственную коллекцию. Это может быть применено к другим функциональным структурам данных, таким как Array, Vector, Queue, Set и Map.

4) flatMap, которая пытается из попыток

Как только вы привыкнете к функциональному программированию с помощью Vavr и начнете использовать Try в общедоступных методах, вскоре вы можете столкнуться с гораздо более распространенным сценарием, когда из контекста Try вы вызываете другой метод, возвращающий Try:

Метод wrapThrowOnXYZ() возвращает Try. В случае успеха мы сопоставляем обернутое значение другому Try, вызывая anotherTryWrapper(). И это оставляет нам Try из Try. Возможны три результата:
- внешний Try - сбой,
- внешний Try - успех, но внутренний Try - сбой,
- внешний Try - успех и внутренний Try - это успех.

Чтобы извлечь результат (Try из Try), мы не можем просто вызвать get() на внешнем Try. Сначала нам нужно проверить, успешно ли работает isSuccess(). В противном случае мы могли бы закончить с выдачей исключения, если Try завершит ошибку, и будет следовать наш профессиональный стиль программирования «не бросать, вернуть попробовать».

Это можно исправить с помощью flatMap:

flatMap либо вернет успех, заключив String, либо один из двух возможных сбоев: исключение из wrapThrowOnXYZ() или исключение из anotherTryWrapper().

Подводя итог: flatMap на Try из Tries возвращает Try.Success, если все Tries успешны или первые Try.Failure, встреченные в цепочке.

5) flatMap тот вариант варианта

В следующем примере показан очень похожий подход, только с Options.
Как только методы возвращают Options, обертывая значение или Option.None, вы столкнетесь с такой ситуацией: из контекста Option вы предоставляете средство сопоставления, возвращающее также Option:

И снова у нас остается 3 возможных результата:
- внешний Option - это None,
- внешний Option - это Some, а внутренний Option - это None,
- внешний Option это Some, а внутренний Option - это Some.

Мы не можем вызвать get() на внешнем Option, чтобы распаковать внутреннее Option, не вызвав сначала isDefined(). В противном случае возникает исключение, если Option является None. Мы хотим, чтобы только один Option был либо None, либо Some. И вот flatMap снова светится.

Подводя итог: flatMap, примененный к Option другого Option, приводит к Option.Some, если все Option равны Some, или Option.None в противном случае.

6) FlatMap that Either of Either (Либо из Либо), либо

Как указывалось ранее, в случае успеха map применяет функцию сопоставления. В случае Either это значение Right. Сказав это, давайте посмотрим, как применить flatMap на Either.

outerEither Either - это
- Either.Right обертывание age String, если age не равно нулю,
- Either.Left обертывание «пусто», если age равно нулю.

Применение flatMap возвращает
- Either.Left упаковка «пуста», если outerEither Either.Left,
- Either.Left упаковка String, которая не может быть проанализирована в Integer,
- Either.Right упаковка Integer, если age может быть успешно проанализирован.

Подводя итог: flatMap на Either другого Either приводит к Either.Right, если все Either равны Right, или Either.Left, завершающий первый встреченный Left.

Все примеры доступны на GitHub, а также имеется набор тестов, позволяющий поэкспериментировать с различными входными данными.

Подведем итоги: есть много способов flatMap можно использовать для обработки данных. Однако теперь должно быть ясно, что значит сопоставить элемент List, Try.Success, Option.Some, завершенный Future или Either.Right, а затем сгладить результат.

Ищете экспертов по Scala и Java?

Свяжитесь с нами!

Мы заставим технологии работать на ваш бизнес. Посмотреть проекты, которые мы успешно реализовали.