El método Stream reduce en Java es uno de los métodos más comunes y usados dentro de la API de Streams y te permite convertir una secuencia de elementos en un único valor. El día de hoy en nuestro artículo te explicaremos qué es el Stream reduce en Java y cómo funciona gracias al método reduce.
¿Qué es el método Stream reduce en Java?
El método Stream reduce en Java es una operación terminal de la API de Streams que permite transformar una secuencia de elementos en un resultado único, por medio de la aplicación de manera iterativa de una función a los elementos del Stream. Si necesitas reducir una colección de datos a un solo valor, cómo calcular la suma, el producto o concatenar elementos de una lista, puedes hacer uso de este método.
Dentro del método reduce tenemos tres conceptos que son clave:
- Identidad: Es el valor inicial del proceso, el cual servirá como base para la acumulación de los resultados. Si no hay más valores en el stream, este será el valor final.
- Acumulador: La función que toma dos elementos: el acumulado actual y el siguiente elemento del stream, y devuelve el nuevo valor acumulado.
- Combinador: Utilizado cuando el stream se procesa en paralelo (parallelStream), para combinar los resultados parciales de diferentes subprocesos.
Ejemplo de Stream reduce en Java
Para este ejemplo tienes una lista de enteros y deseas sumar todos sus elementos. En Java tradicional, esto se haría con un bucle for
. Pero con el método reduce, puedes simplificarlo. Veamos una comparación entre ambas formas:
- Enfoque clásico con un bucle:
List<Integer> gastos = Arrays.asList(100, 200, 300);
int total = 0;
for (int gasto : gastos) {
total += gasto;
}
System.out.println(total); // Imprime 600
- Enfoque con Stream reduce en Java:
Usando el método stream reduce en Java, puedes simplificar el código y hacerlo más legible:
List<Integer> gastos = Arrays.asList(100, 200, 300);
int total = gastos.stream().reduce(0, (acumulador, numero) -> acumulador + numero);
System.out.println(total); // Imprime 600
En este ejemplo:
- 0 es la identidad, el valor inicial de la suma.
- (acumulador, numero) -> acumulador + numero es la función de acumulación que toma el valor actual y lo suma al siguiente elemento.
Simplificación con referencias a métodos
Aún podemos simplificar más el ejemplo usando referencias a métodos. En lugar de definir una lambda explícita, podemos usar Integer::sum
, que es una referencia al método estático sum
de la clase Integer
.
int total = gastos.stream().reduce(0, Integer::sum);
System.out.println(total); // Imprime 600
Uso de Optional en reduce
El método reduce
también puede devolver un Optional cuando no se define un valor de identidad. Esto es útil cuando no estás seguro de si el stream tiene elementos y no quieres que el programa falle:
List<Integer> gastos = Arrays.asList(100, 200, 300);
Optional<Integer> total = gastos.stream().reduce((acumulador, numero) -> acumulador + numero);
total.ifPresent(System.out::println); // Imprime 600 si hay elementos
¿Por qué Optional? El Optional es un contenedor que puede o no contener un valor. En este caso, si el stream está vacío, no obtendrás una excepción, sino un Optional vacío que puedes manejar adecuadamente.
Concatenación de Strings con reduce
El método stream reduce en Java no solo sirve para números. También puedes usarlo para otras operaciones como la concatenación de cadenas. En el siguiente ejemplo tienes una lista de nombres y quieres unirlos en una sola cadena:
List<String> nombres = Arrays.asList("Juan", "Gema", "María");
String concatenado = nombres.stream().reduce("", (acumulador, nombre) -> acumulador + nombre);
System.out.println(concatenado); // Imprime "JuanGemaMaría"
En este caso, usamos ""
como identidad para representar una cadena vacía, y luego concatenamos cada nombre en la lista.
Uso del combinador en streams paralelos
Cuando trabajamos con parallelStream (Streams en paralelo), es importante el uso del combinador. El combinador es la función que combina los resultados parciales generados en diferentes hilos. Cuando trabajas con grandes cantidades de datos y deseas mejorar el rendimiento procesando partes del stream en paralelo, puedes hacer uso de él, te será de gran utilidad.
Veamos un ejemplo en el que sumamos la edad de varios coches procesados en paralelo:
List<Car> cars = Arrays.asList(new Car("Mustang", 10), new Car("Megane", 35), new Car("Toledo", 21));
int totalEdad = cars.parallelStream()
.reduce(0, (partialResult, car) -> partialResult + car.getAge(), Integer::sum);
System.out.println(totalEdad); // Imprime 66
En este ejemplo:
- partialResult representa el resultado parcial de cada fragmento del stream.
- Integer::sum actúa como combinador para sumar los resultados de los diferentes subprocesos.
Si este tema ha sido de tu interés y quieres ahondar más en el campo de la programación con este lenguaje famoso, puedes suscribirte a nuestro curso sobre java, en donde sentarás las bases teóricas y podrás llevarlas a la práctica mediante la creación de tu primer hola mundo en Java. ¡No esperes más y cambia tu vida ahora!