Разликата между map () и flatMap ()

1. Общ преглед

API (map) и flatMap () произлизат от функционални езици. В Java 8 можете да ги намерите в Optional, Stream и CompletableFuture (макар и с малко по-различно име).

Потоците представляват последователност от обекти, докато опционалните са класове, които представляват стойност, която може да присъства или отсъства. Сред другите съвкупни операции имаме методите map () и flatMap () .

Въпреки факта, че и двете имат едни и същи видове връщане , те са доста различни. Нека да обясним тези разлики, като анализираме някои примери за потоци и опции.

2. Карта и Flatmap в Optionals

Методът map () работи добре с по избор - ако функцията връща точния тип, от който се нуждаем:

Optional s = 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")));

Както виждаме, в крайна сметка получаваме вложената структура по избор . Въпреки че работи, това е доста тромаво за използване и не осигурява допълнителна нулева безопасност, така че е по-добре да запазите плоска структура.

Точно това ни помага flatMap () :

assertEquals(Optional.of("STRING"), Optional .of("string") .flatMap(s -> Optional.of("STRING")));

3. Карта и Flatmap в потоци

И двата метода работят по подобен начин по избор .

Методът map () обгръща основната последователност в екземпляр на Stream , докато методът flatMap () позволява да се избегне вложен Stream структура.

В следващия пример map () създава поток, състоящ се от резултатите от прилагането на метода toUpperCase () към елементите на входния поток:

List myList = 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 той flatMap () метод първо се изравнява входния поток от предавания на живо на Strings (за повече за изправяне, вижте статията). След това работи подобно на метода map () .

4. Заключение

Java 8 ни дава възможност да използваме методите map () и flatMap () , които първоначално са били използвани във функционални езици.

Можем да ги извикаме в Streams и Optionals. Тези методи ни помагат да получаваме картографирани обекти, като прилагаме предоставената функция за картографиране.

Както винаги, можете да разгледате примерите, предоставени в тази статия, в GitHub.