membersound
membersound

Reputation: 86925

How to sum a list of integers with java streams?

I want to sum a list of Integers. It works as follows, but the syntax does not feel right. Could the code be optimized?

Map<String, Integer> integers;
integers.values().stream().mapToInt(i -> i).sum();

Upvotes: 503

Views: 636231

Answers (14)

Ramesh Papaganti
Ramesh Papaganti

Reputation: 7861

With List.of

List<Integer> numbers = List.of(1, 2, 3, 4, 5);
int sum = numbers.stream().mapToInt(Integer::intValue).sum();

With IntStream.of

int[] numbers = {1, 2, 3, 4, 5};
       
int sum = IntStream.of(numbers).reduce(0, Integer::sum);
   
int sum = IntStream.of(1, 2, 3, 4, 5).sum();

Upvotes: 0

Jay Patel
Jay Patel

Reputation: 71

Using summingInt

Integer sum= listInt.stream().collect(Collectors.summingInt(Integer::intValue));

Upvotes: 1

Nagappa L M
Nagappa L M

Reputation: 1480

IntStream.of(1, 2, 23).sum();
IntStream.of(1, 2, 23,1, 2, 23,1, 2, 23).max().getAsInt();

Upvotes: 2

Saša
Saša

Reputation: 4808

There is one more option no one considered here and it reflects on usage of multi-core environment. If you want to use its advantages, then next code should be used instead of the other mentioned solutions:

int sum = integers.values().parallelStream().mapToInt(Integer::intValue)
        .reduce(0, Integer::sum, Integer::sum);

This solution is similar to other ones, but please notice the third argument in reduce. It tells compiler what to do with partial summaries calculated in different chunks of the stream, by different threads. Also instead of stream(), the parallelStream() is used. In this case it would just summarize it. The other option to put as third argument is (i, j) -> i + j, which means that it would add a value of a stream chunk (j) to the current value (i) and use it as a current value for the next stream chunk until all partial results are processed.

Even when using plain stream() it is useful to tell to reduce what to do with stream chunks' summaries, just in case someone, or you, would like to parallelize it in the future. The initial development is best time for that, since later on you need to remember what this is supposed to be and need to spend some time in understanding the purpose of that code again.

And of course instead of method reference operator you can have different dialect of lambda. I prefer it this way as more compact and still easy readable.

Also remember this can be used for more complex calculations too, but always be aware there are no guarantees about sequence and deployment of stream elements to threads.

Upvotes: 3

rogerdpack
rogerdpack

Reputation: 66951

Unfortunately looks like the Stream API only returns normal streams from, say, List<Integer>#stream(). Guess they're pretty much forced to because of how generics work.

These normal Streams are of generic objects so don't have specialized methods like sum() etc. so you have to use the weird re-stream "looks like a no-op" conversion by default to get to those methods... .mapToInt(i -> i).

Another option is using "Eclipse Collections" which are like an expanded java Stream API

IntLists.immutable.ofAll(integers.values()).sum();

Upvotes: 2

Necreaux
Necreaux

Reputation: 9786

This will work, but the i -> i is doing some automatic unboxing which is why it "feels" strange. mapToInt converts the stream to an IntStream "of primitive int-valued elements". Either of the following will work and better explain what the compiler is doing under the hood with your original syntax:

integers.values().stream().mapToInt(i -> i.intValue()).sum();
integers.values().stream().mapToInt(Integer::intValue).sum();

Upvotes: 667

itro
itro

Reputation: 7228

May this help those who have objects on the list.

If you have a list of objects and wanted to sum specific fields of this object use the below.

List<ResultSom> somList = MyUtil.getResultSom();
BigDecimal result= somList.stream().map(ResultSom::getNetto).reduce(
                                             BigDecimal.ZERO, BigDecimal::add);

Upvotes: 9

JDGuide
JDGuide

Reputation: 6525

I have declared a list of Integers.

ArrayList<Integer> numberList = new ArrayList<Integer>(Arrays.asList(1, 2, 3, 4, 5));

You can try using these different ways below.

Using mapToInt

int sum = numberList.stream().mapToInt(Integer::intValue).sum();

Using summarizingInt

int sum = numberList.stream().collect(Collectors.summarizingInt(Integer::intValue)).getSum();

Using reduce

int sum = numberList.stream().reduce(Integer::sum).get().intValue();

Upvotes: 14

Sachith Dickwella
Sachith Dickwella

Reputation: 1490

This would be the shortest way to sum up int type array (for long array LongStream, for double array DoubleStream and so forth). Not all the primitive integer or floating point types have the Stream implementation though.

IntStream.of(integers).sum();

Upvotes: 6

Johnson Abraham
Johnson Abraham

Reputation: 361

You can use reduce() to sum a list of integers.

int sum = integers.values().stream().reduce(0, Integer::sum);

Upvotes: 23

Ashish Jha
Ashish Jha

Reputation: 336

You can use collect method to add list of integers.

List<Integer> list = Arrays.asList(2, 4, 5, 6);
int sum = list.stream().collect(Collectors.summingInt(Integer::intValue));

Upvotes: 18

Saeed Zarinfam
Saeed Zarinfam

Reputation: 10200

You can use reduce method:

long sum = result.stream().map(e -> e.getCreditAmount()).reduce(0L, (x, y) -> x + y);

or

long sum = result.stream().map(e -> e.getCreditAmount()).reduce(0L, Integer::sum);

Upvotes: 35

Alex Salauyou
Alex Salauyou

Reputation: 14348

I suggest 2 more options:

integers.values().stream().mapToInt(Integer::intValue).sum();
integers.values().stream().collect(Collectors.summingInt(Integer::intValue));

The second one uses Collectors.summingInt() collector, there is also a summingLong() collector which you would use with mapToLong.


And a third option: Java 8 introduces a very effective LongAdder accumulator designed to speed-up summarizing in parallel streams and multi-thread environments. Here, here's an example use:

LongAdder a = new LongAdder();
map.values().parallelStream().forEach(a::add);
sum = a.intValue();

Upvotes: 185

J Atkin
J Atkin

Reputation: 3150

From the docs

Reduction operations A reduction operation (also called a fold) takes a sequence of input elements and combines them into a single summary result by repeated application of a combining operation, such as finding the sum or maximum of a set of numbers, or accumulating elements into a list. The streams classes have multiple forms of general reduction operations, called reduce() and collect(), as well as multiple specialized reduction forms such as sum(), max(), or count().

Of course, such operations can be readily implemented as simple sequential loops, as in:

int sum = 0;
for (int x : numbers) {
   sum += x;
}

However, there are good reasons to prefer a reduce operation over a mutative accumulation such as the above. Not only is a reduction "more abstract" -- it operates on the stream as a whole rather than individual elements -- but a properly constructed reduce operation is inherently parallelizable, so long as the function(s) used to process the elements are associative and stateless. For example, given a stream of numbers for which we want to find the sum, we can write:

int sum = numbers.stream().reduce(0, (x,y) -> x+y);

or:

int sum = numbers.stream().reduce(0, Integer::sum);

These reduction operations can run safely in parallel with almost no modification:

int sum = numbers.parallelStream().reduce(0, Integer::sum);

So, for a map you would use:

integers.values().stream().mapToInt(i -> i).reduce(0, (x,y) -> x+y);

Or:

integers.values().stream().reduce(0, Integer::sum);

Upvotes: 101

Related Questions