¿Cómo sumar una lista de números enteros con secuencias de Java?
Quiero resumir una lista de números enteros. Funciona de la siguiente manera, pero la sintaxis no parece correcta. ¿Se podría optimizar el código?
Map<String, Integer> integers;
integers.values().stream().mapToInt(i -> i).sum();
Esto funcionará, pero se i -> i
está realizando un desembalaje automático, por lo que "se siente" extraño. mapToInt
convierte la secuencia en IntStream
"de elementos primitivos con valores int". Cualquiera de los siguientes funcionará y explicará mejor lo que hace el compilador bajo el capó con su sintaxis original:
integers.values().stream().mapToInt(i -> i.intValue()).sum();
integers.values().stream().mapToInt(Integer::intValue).sum();
Sugiero 2 opciones más:
integers.values().stream().mapToInt(Integer::intValue).sum();
integers.values().stream().collect(Collectors.summingInt(Integer::intValue));
El segundo usa Collectors.summingInt()
un recopilador, también hay un summingLong()
recopilador que usarías con mapToLong
.
Y una tercera opción: Java 8 introduce un acumulador muy eficaz LongAdder
diseñado para acelerar el resumen en flujos paralelos y entornos multiproceso. A continuación se muestra un ejemplo de uso:
LongAdder a = new LongAdder();
map.values().parallelStream().forEach(a::add);
sum = a.intValue();
De los documentos
Operaciones de reducción Una operación de reducción (también llamada pliegue) toma una secuencia de elementos de entrada y los combina en un único resultado resumido mediante la aplicación repetida de una operación de combinación, como encontrar la suma o el máximo de un conjunto de números, o acumular elementos en una lista. Las clases de flujos tienen múltiples formas de operaciones de reducción generales, llamadas reduce() y Collect(), así como múltiples formas de reducción especializadas como sum(), max() o count().
Por supuesto, dichas operaciones se pueden implementar fácilmente como bucles secuenciales simples, como en:
int sum = 0; for (int x : numbers) { sum += x; }
Sin embargo, existen buenas razones para preferir una operación de reducción a una acumulación mutativa como la anterior. Una reducción no sólo es "más abstracta" (opera en la secuencia como un todo en lugar de elementos individuales) sino que una operación de reducción construida correctamente es inherentemente paralelizable, siempre que las funciones utilizadas para procesar los elementos sean asociativas. y apátrida. Por ejemplo, dada una serie de números cuya suma queremos encontrar, podemos escribir:
int sum = numbers.stream().reduce(0, (x,y) -> x+y);
o:
int sum = numbers.stream().reduce(0, Integer::sum);
Estas operaciones de reducción pueden realizarse de forma segura en paralelo casi sin modificaciones:
int sum = numbers.parallelStream().reduce(0, Integer::sum);
Entonces, para un mapa usarías:
integers.values().stream().mapToInt(i -> i).reduce(0, (x,y) -> x+y);
O:
integers.values().stream().reduce(0, Integer::sum);