1. Обзор
map() и flatMap() API происходят из функциональных языков. В Java 8 мы можем найти их в Optional , Stream и в CompletableFuture (хотя и под немного другим именем).
Потоки представляют собой последовательность объектов, в то время как необязательными являются классы, представляющие значение, которое может присутствовать или отсутствовать. Среди других агрегатных операций у нас есть методы map() и flatMap () .
Несмотря на то, что оба имеют одинаковые типы возврата, они совершенно разные. Давайте объясним эти различия, проанализировав некоторые примеры потоков и необязательных.
Дальнейшее чтение:
Итерация по карте в Java
Сериализация и десериализация карт с помощью Джексона
Как хранить дубликаты ключей на карте в Java?
2. Карта и плоская карта в необязательном
Метод map() хорошо работает с Необязательным — если функция возвращает точный тип, который нам нужен:
Optionals = Optional.of("test"); assertEquals(Optional.of("TEST"), s.map(String::toUpperCase));
Однако в более сложных случаях нам может быть предоставлена функция, которая также возвращает Необязательный . В таких случаях использование map() приведет к вложенной структуре, так как реализация map() выполняет дополнительную внутреннюю обертку.
Давайте рассмотрим другой пример, чтобы лучше понять эту ситуацию:
assertEquals(Optional.of(Optional.of("STRING")), Optional .of("string") .map(s -> Optional.of("STRING")));
Как мы видим, в итоге мы получаем вложенную структуру Optional> . Хотя он работает, он довольно громоздок в использовании и не обеспечивает никакой дополнительной нулевой безопасности, поэтому лучше сохранить плоскую структуру.
Это именно то, что flatMap() помогает нам сделать:
assertEquals(Optional.of("STRING"), Optional .of("string") .flatMap(s -> Optional.of("STRING")));
3. Карта и плоская карта в потоках
Оба метода работают одинаково для Необязательно .
Метод map() обертывает базовую последовательность в экземпляр Stream , в то время как метод flatMap() позволяет избежать вложенной структуры Stream>|/.
Здесь map() создает Поток , состоящий из результатов применения метода toUpperCase() к элементам входного потока :
ListmyList = Stream.of("a", "b") .map(String::toUpperCase) .collect(Collectors.toList()); assertEquals(asList("A", "B"), myList);
map() работает довольно хорошо в таком простом случае. Но что, если у нас есть что-то более сложное, например, список списков в качестве входных данных?
Давайте посмотрим, как это работает:
List> list = Arrays.asList( Arrays.asList("a"), Arrays.asList("b")); System.out.println(list);
Этот фрагмент выводит список списков [[a], [b]] .
Теперь давайте использовать flatMap() :
System.out.println(list .stream() .flatMap(Collection::stream) .collect(Collectors.toList()));
Результат такого фрагмента будет сглажен до [a, b] .
T he flatMap() метод сначала выравнивает входной поток из потоков в Поток из Строк (подробнее о выравнивании см. В этой статье ). После этого он работает аналогично методу map () .
4. Заключение
Java 8 дает нам возможность использовать методы map() и flatMap () , которые первоначально использовались в функциональных языках.
Мы можем вызывать их в потоках и необязательно. Эти методы помогают нам получить сопоставленные объекты, применяя предоставленную функцию сопоставления.
Как всегда, примеры в этой статье доступны на GitHub .