Java 8 tips: collectingAndThen en Streams

Como apasionado de java que soy, la última versión me ha encantado por todos los cambios y mejoras que incluye. Por ello, comienzo hoy una nueva serie de posts relacionados con Java 8,  serán pequeños posts con curiosidades que me hayan llamado la atención o ‘tips’ que me parezcan especialmente útiles de la actual versión de la JDK.

Empiezo este, con un método interesante de la clase Collectors, usada al «terminar» un stream, para agrupar los elementos.

Concepto

Los Streams en java constan principalmente de 2 tipos de métodos u operaciones que pueden realizarse sobre ellos:

  • intermediate operations
  • terminal operations

Las ‘terminal’ son operaciones que pueden verse como operaciones para obtener un resultado final del stream (ya sea para obtener una lista, un sumatorio, etc).

Una de las más comunes es ‘collect‘:

   List<String> characters = Stream.of("Geralt", "Triss", "Yennefer", "Cirilla")
                                        .collect(Collectors.toList());

Lo que hace es agrupar los datos del stream y devolverlos en una Collection. En este caso, en un List.

Collectors.collectingAndThen

Imaginemos ahora que en el ejemplo anterior queremos que el list que nos devuelva el stream sea una lista inmutable. La idea es hacer esto:

        List<String> characters = Stream.of("Geralt", "Triss", "Yennefer", "Cirilla")
                                        .collect(Collectors.toList());
        List<String> charactersImmutable = Collections.unmodifiableList(characters);

Con Java 8 podemos hacerlo de una manera más elegante, usando el método ‘collectingAndThen‘ de Collectors:

    List<String> charactersImmutable =
                Stream.of("Geralt", "Triss", "Yennefer", "Cirilla")
                      .collect(Collectors.collectingAndThen(Collectors.toList(),
                                                            c -> Collections.unmodifiableList(c)));

Como vemos, ‘collectingAndThen’ nos proporciona la posibilidad de realizar una tarea ‘extra’ después de realizar el ‘collect’ en si mismo. En este caso, una vez obtenido el List, creamos con él una lista inmutable, que es lo que al final devolverá todo el procesamiento del stream.

Y por supuesto, podemos hacerlo más limpio aún, haciendo que sea una ‘method reference’:

    List<String> charactersImmutable =
                Stream.of("Geralt", "Triss", "Yennefer", "Cirilla")
                      .collect(Collectors.collectingAndThen(Collectors.toList(),
                                                            Collections::unmodifiableList));

El método ‘unmodifiableList‘ de Collections puede usarse perfectamente como ‘method reference’, quedando más limpio el código.

Gracias al método ‘collectingAndThen’ de Collectors podemos realizar alguna acción sobre la Collection (List, Map, etc) que queramos sacar del stream, antes de devolverla, quedando el código mucho más elegante 🙂

Espero que os sea útil. Tenéis el código de este post en mi github, proyecto java8-collectingandthen-example.