¿Cómo sumar una lista de números enteros con secuencias de Java?

Resuelto membersound asked hace 9 años • 13 respuestas

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();
membersound avatar May 08 '15 20:05 membersound
Aceptado

Esto funcionará, pero se i -> iestá realizando un desembalaje automático, por lo que "se siente" extraño. mapToIntconvierte 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();
Necreaux avatar May 08 '2015 13:05 Necreaux

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 LongAdderdiseñ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();
Alex Salauyou avatar May 08 '2015 13:05 Alex Salauyou

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);
J Atkin avatar May 08 '2015 13:05 J Atkin