Los Stream Co­lle­c­to­rs son una potente función de la Java 8 Stream API que permiten recoger y procesar datos de forma eficiente. Ex­pli­ca­mos la es­tru­c­tu­ra y los posibles usos del método Java Collect.

¿Cuáles son los ámbitos de apli­ca­ción de Java Collect()?

Un Stream Collector puede uti­li­zar­se para crear una lista, un conjunto o un mapa a partir de un flujo (stream). Un stream es una secuencia de elementos que se procesan uno tras otro. La interfaz del Collector pro­po­r­cio­na una serie de ope­ra­cio­nes de reducción para los datos en un flujo de ca­na­li­za­ción. Estas son ope­ra­cio­nes finales que recopilan y fusionan los re­su­l­ta­dos de los pasos in­te­r­me­dios.

Los co­lle­c­to­rs pueden ser uti­li­za­dos, por ejemplo, para filtrar o cla­si­fi­car objetos de un stream. También es posible realizar agre­ga­cio­nes, como la suma de números, la co­n­ca­te­na­ción de cadenas o el conteo de elementos. Además, los co­lle­c­to­rs disponen de funciones para tra­n­s­fo­r­mar el contenido de un stream en una es­tru­c­tu­ra de­te­r­mi­na­da. De esta forma, por ejemplo, se puede convertir una lista en un mapa. Las agru­pa­cio­nes ayudan a ca­te­go­ri­zar los elementos con de­te­r­mi­na­das pro­pie­da­des o co­n­di­cio­nes. Sin embargo, la mayor ventaja de los stream co­lle­c­to­rs es que permiten procesar datos de manera paralela uti­li­za­n­do múltiples threads (hilos). Esto permite que las ope­ra­cio­nes, sobre todo con grandes ca­n­ti­da­des de datos, se realicen de manera más rápida y eficiente.

La sintaxis de Java Collect()

Este método recibe como argumento un collector que indica cómo re­co­le­c­tar y agregar los elementos del stream. Un collector es una interfaz que ofrece di­fe­re­n­tes métodos para agrupar los elementos del stream de una forma es­pe­cí­fi­ca, como una lista, un conjunto o un mapa.

Existen dos métodos en Java Collect:

  1. <R> R collect(Supplier<R> supplier, Bi­Co­n­su­mer<R, ? super T> ac­cu­mu­la­tor,Bi­Co­n­su­mer<R, R> combiner)
  2. <R, A> R collect(Collector<? super T, A, R> collector)

La primera variante tiene tres funciones como ar­gu­me­n­tos:

  • supplier: crea un container que se utiliza para los re­su­l­ta­dos in­te­r­me­dios.
  • ac­cu­mu­la­tor: calcula el resultado final.
  • combiner: combina los re­su­l­ta­dos de ope­ra­cio­nes de flujo paralelas.

Estos co­lle­c­to­rs pre­de­fi­ni­dos ya están incluidos en la bi­blio­te­ca estándar y pueden im­po­r­tar­se y uti­li­zar­se fá­ci­l­me­n­te.

La segunda variante toma un collector como argumento y devuelve el resultado.

  • R: el tipo del resultado
  • T: el tipo de los elementos del stream
  • A: el tipo del ac­cu­mu­la­tor que almacena el estado in­te­r­me­dio de la operación del collector
  • collector: realiza la operación de reducción.

Mediante esta variante, los de­sa­rro­lla­do­res tienen la po­si­bi­li­dad de crear co­le­c­to­res pe­r­so­na­li­za­dos que se ajustan es­pe­cí­fi­ca­me­n­te a sus ne­ce­si­da­des, dando así una mayor fle­xi­bi­li­dad y control al proceso de reducción.

Ejemplos prácticos del uso de Java Collect()

A co­n­ti­nua­ción, pre­se­n­ta­mos varias funciones del método Stream.collect() para ilustrar su uso. Es re­co­me­n­da­ble que estés fa­mi­lia­ri­za­do con los ope­ra­do­res Java antes de ade­n­trar­te en el co­lle­c­tion framework.

Co­n­ca­te­nar una lista de cadenas

Con Java Collect() puedes co­n­ca­te­nar una lista de cadenas para obtener una nueva cadena:

List<String> letters = List.of("a", "b", "c", "d", "e");
// without combiner function
StringBuilder result = letters.stream().collect(StringBuilder::new, (x, y) -> x.append(y),
    (a, b) -> a.append(",").append(b));
System.out.println(result.toString());
// with combiner function
StringBuilder result1 = letters.parallelStream().collect(StringBuilder::new, (x, y) -> x.append(y),
    (a, b) -> a.append(",").append(b));
System.out.println(result1.toString());
Java

Obtenemos este resultado:

abcde
a, b, c, d, e
Java

En el primer cálculo, solo hay una instancia Stri­n­g­Bui­l­der y no se ha utilizado ninguna función co­m­bi­na­do­ra. Por lo tanto, el resultado es abcde.

En el segundo resultado, vemos que la función co­m­bi­na­do­ra ha fusionado las in­s­ta­n­cias Stri­n­g­Bui­l­der y las ha separado con una coma.

Recoger los elementos de una lista con toList()

Podemos se­le­c­cio­nar ciertos elementos de una lista con la función filter() y al­ma­ce­nar­los en una nueva lista con toList().

List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6, 7);
List<Integer> oddNumbers = numbers.stream().filter(x -> x % 2 != 0).collect(Collectors.toList());
System.out.println(oddNumbers);
Java

La nueva lista ahora solo contiene números impares:

[1, 3, 5, 7]
Java

Recoger los elementos de un conjunto con toSet()

De la misma forma, podemos crear un nuevo conjunto (set) a partir de los elementos se­le­c­cio­na­dos. El orden en un conjunto puede ser no ordenado.

List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6, 7);
Set<Integer> evenNumbers = numbers.parallelStream().filter(x -> x % 2 == 0).collect(Collectors.toSet());
System.out.println(evenNumbers);
Java

Esto nos da este resultado:

[2, 4, 6]
Java

Recopilar elementos en un mapa con toMap()

Un mapa en conjunto con Collect() de Java asigna a cada clave un valor.

List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6, 7);
Map<Integer, String> mapEvenNumbers = numbers.parallelStream().filter(x -> x % 2 == 0)
    .collect(Collectors.toMap(Function.identity(), x -> String.valueOf(x)));
System.out.println(mapEvenNumbers);
Java

En el resultado vemos que la entrada formada por números pares ha sido asignada a sus valores idénticos:

{2=2, 4=4, 6=6}
Java

Combinar elementos de una cadena con joining()

El método joining() añade cada elemento del flujo en el orden en que aparecen y utiliza un separador para separar los elementos. El separador se pasa como argumento a joining(). Si no se es­pe­ci­fi­ca ningún separador, joining() utiliza la cadena vacía "".

jshell> String result1 = Stream.of("a", "b", "c").collect(Collectors.joining());
jshell> String result2 = Stream.of("a", "b", "c").collect(Collectors.joining(",", "{", "}"));
Java

Los re­su­l­ta­dos son los si­guie­n­tes:

result1 ==> "abc"
result2 ==> "{a,b,c}"
Java
Ir al menú principal