La reducción normal está destinada a combinar dos valores inmutables como int, double, etc. y producir uno nuevo; Es una reducción inmutable . En contraste, el método de recolección está diseñado para mutar un contenedor para acumular el resultado que se supone que debe producir.
Para ilustrar el problema, supongamos que desea lograrlo Collectors.toList()
usando una reducción simple como
List<Integer> numbers = stream.reduce(
new ArrayList<Integer>(),
(List<Integer> l, Integer e) -> {
l.add(e);
return l;
},
(List<Integer> l1, List<Integer> l2) -> {
l1.addAll(l2);
return l1;
});
Este es el equivalente de Collectors.toList()
. Sin embargo, en este caso mutas el List<Integer>
. Como sabemos ArrayList
, no es seguro para subprocesos, ni es seguro agregar / eliminar valores mientras itera, por lo que obtendrá una excepción concurrente ArrayIndexOutOfBoundsException
o cualquier tipo de excepción (especialmente cuando se ejecuta en paralelo) cuando actualiza la lista o el combinador intenta fusionar las listas porque está mutando la lista acumulando (agregando) los enteros. Si desea hacer que este hilo sea seguro, debe pasar una nueva lista cada vez que perjudicaría el rendimiento.
En contraste, las Collectors.toList()
obras de manera similar. Sin embargo, garantiza la seguridad del hilo cuando acumula los valores en la lista. De la documentación para el collect
método :
Realiza una operación de reducción mutable en los elementos de esta secuencia utilizando un recopilador. Si la secuencia es paralela, y el recopilador es concurrente, y la secuencia no está ordenada o el recopilador no está ordenado, se realizará una reducción concurrente. Cuando se ejecuta en paralelo, se pueden instanciar, completar y fusionar múltiples resultados intermedios para mantener el aislamiento de las estructuras de datos mutables. Por lo tanto, incluso cuando se ejecuta en paralelo con estructuras de datos no seguras para subprocesos (como ArrayList), no se necesita sincronización adicional para una reducción paralela.
Entonces para responder a su pregunta:
¿Cuándo usarías collect()
vs reduce()
?
si tiene valores inmutables, tales como ints
, doubles
, Strings
a continuación, la reducción de lo normal funciona bien. Sin embargo, si tiene que decir reduce
sus valores para decir una List
(estructura de datos mutable), entonces necesita usar la reducción mutable con el collect
método.