1. Información general
Las API map () y flatMap () provienen de lenguajes funcionales. En Java 8, puede encontrarlos en Optional, Stream y en CompletableFuture (aunque con un nombre ligeramente diferente).
Los flujos representan una secuencia de objetos, mientras que los opcionales son clases que representan un valor que puede estar presente o ausente. Entre otras operaciones agregadas, tenemos los métodos map () y flatMap () .
A pesar de que ambos tienen los mismos tipos de devolución , son bastante diferentes. Expliquemos estas diferencias analizando algunos ejemplos de corrientes y opcionales.
2. Mapa y mapa plano en opcionales
El método map () funciona bien con Opcional , si la función devuelve el tipo exacto que necesitamos:
Optional s = Optional.of("test"); assertEquals(Optional.of("TEST"), s.map(String::toUpperCase));
Sin embargo, en casos más complejos, es posible que recibamos una función que también devuelva un Opcional . En tales casos, el uso de map () conduciría a una estructura anidada, ya que la implementación de map () realiza un ajuste adicional internamente.
Veamos otro ejemplo para comprender mejor esta situación:
assertEquals(Optional.of(Optional.of("STRING")), Optional .of("string") .map(s -> Optional.of("STRING")));
Como podemos ver, terminamos con la estructura anidada Opcional
Eso es exactamente lo que flatMap () nos ayuda a hacer:
assertEquals(Optional.of("STRING"), Optional .of("string") .flatMap(s -> Optional.of("STRING")));
3. Mapa y mapa plano en arroyos
Ambos métodos funcionan de manera similar para Opcional .
El método map () envuelve la secuencia subyacente en una instancia de Stream , mientras que el método flatMap () permite evitar Stream
anidado
En el siguiente ejemplo, map () produce un Stream que consta de los resultados de aplicar el método toUpperCase () a los elementos del Stream de entrada :
List myList = Stream.of("a", "b") .map(String::toUpperCase) .collect(Collectors.toList()); assertEquals(asList("A", "B"), myList);
map () funciona bastante bien en un caso tan simple, pero ¿qué pasa si tenemos algo más complejo como una lista de listas como entrada?
Vamos a ver cómo funciona:
List
list = Arrays.asList( Arrays.asList("a"), Arrays.asList("b")); System.out.println(list);
Este fragmento imprime una lista de listas [[a], [b]].
Ahora, usemos un flatMap () :
System.out.println(list .stream() .flatMap(Collection::stream) .collect(Collectors.toList()));
El resultado de dicho fragmento se acoplará a [a, b].
T él flatMap () método se aplana primera entrada de la corriente de arroyos a una corriente de Cuerdas (para más información sobre el acoplamiento, consulte el artículo). A partir de entonces, funciona de manera similar al método map () .
4. Conclusión
Java 8 nos da la oportunidad de usar los métodos map () y flatMap () que originalmente se usaban en lenguajes funcionales.
Podemos invocarlos en Streams y Optionals. Estos métodos nos ayudan a obtener objetos mapeados aplicando la función de mapeo proporcionada.
Como siempre, puede consultar los ejemplos proporcionados en este artículo en GitHub.