Summing method in Collectors API

  • Last Updated: April 11, 2024
  • By: javahandson
  • Series
img

Summing method in Collectors API

The summing method in Collectors API adds up one numeric property across a whole stream of objects. This guide covers summingInt, summingLong, and summingDouble with examples, the silent overflow trap, per-group totals, and interview questions.

1. Introduction

Adding numbers is the first thing anyone learns to program. Then you meet a list of objects, and suddenly it gets fiddly again.

You do not want to add the objects. You want to add one field inside them. Every student has marks, every order has an amount, every file has a size, and you need the total of just that one field.

The old way declares a variable, loops, and accumulates. It works fine, and it takes four lines to say something very simple.

Java 8 offers a one-line answer. Hand a summing collector a method reference, and it pulls that field out of every element and totals it for you.

// The loop
int total = 0;
for (Student student : studentList) {
    total += student.getMarks();
}

// The collector
int total = studentList.stream()
        .collect(Collectors.summingInt(Student::getMarks));

Java gives you three of these, one per numeric type. They look almost identical, and one of them will silently give you a wrong answer if you pick it carelessly. Let us see why.

1.1 What This Article Covers

We work through each variant, then look at where these collectors genuinely beat a plain loop. Here is the plan:

  • What the summing collectors do, and why they return wrapper types
  • summingInt, summingLong, and summingDouble, signature by signature
  • The silent overflow that catches people out
  • Per-group totals with groupingBy and partitioningBy
  • Alternatives such as mapToInt, summarizingInt, and reducing
  • Six common mistakes, a full walkthrough, and interview questions

You need a little stream experience to follow along. Our guides on lambda expressions and method references cover the syntax we lean on.

2. What the Summing Collectors Do

Three methods, one job. Each pulls a number out of every element and adds them all together.

2.1 One Property, One Total

Picture a stack of exam papers. You flip through them one at a time, read the mark in the corner, and keep a running total in your head. At the end you have one number.

That is the whole idea. The collector never looks at the rest of the object. It calls your extractor, takes the number it gets back, and adds it to the running total.

The extractor is the part you supply. Write it as a method reference such as Student::getMarks, or as a lambda such as s -> s.getMarks(). Both read the same field.

2.2 Where They Live

All three sit in java.util.stream.Collectors, beside toList, groupingBy, and the other factory methods.

  • Every one of them is static, so you call it as Collectors.summingInt(…)
  • Each returns a Collector, which you pass to stream.collect(…)
  • Java 8 shipped all three at once, and the signatures have not changed
  • None of them ever returns null, not even on an empty stream

Our introduction to the Collectors class lays out the wider family.

2.3 They Return Wrappers, Not Primitives

Here is a detail that trips people up later. A Collector must produce an object, because generics cannot hold a primitive. So these three return Integer, Long, and Double, not int, long, and double.

// Collectors.summingInt gives you an Integer
Integer boxed = studentList.stream()
        .collect(Collectors.summingInt(Student::getMarks));

// Assigning to int works, because Java unboxes it for you
int plain = studentList.stream()
        .collect(Collectors.summingInt(Student::getMarks));

Most of the time you never notice, since Java unboxes automatically. The wrapper does bite in one specific place, and section 10.1 shows exactly where.

3. The Three Variants at a Glance

Learn the shape once and all three follow. Only the numeric type moves.

3.1 The Comparison Table

Method Mapper Returns Empty stream
summingInt ToIntFunction Integer 0
summingLong ToLongFunction Long 0
summingDouble ToDoubleFunction Double 0.0

That last column is a small kindness. An empty stream gives you a clean zero, so no Optional and no null check.

3.2 Picking the Right One

Matching the variant to your getter is the obvious start. Thinking about the total is the part people skip.

  • Small int values that cannot add up past two billion? summingInt is fine
  • Many int values, or genuinely large ones? Move up to summingLong
  • A long field such as an id, a byte count, or a timestamp needs summingLong
  • Prices, rates, and measurements belong in summingDouble
  • Real currency deserves neither, and section 9.3 explains what to use instead

Notice the second point. The type of your field is not the only question. The size of the answer matters just as much.

4. The summingInt Method

Start here, since the other two are the same method with one word changed.

4.1 The Syntax

public static <T> Collector<T, ?, Integer>
        summingInt(ToIntFunction<? super T> mapper)

4.2 Reading the Signature

Four pieces, and none of them is hard on its own.

Begin with public static. The method belongs to the class, so you always write Collectors.summingInt(…).

Then <T> stands for whatever your stream carries. Stream a list of Student objects and T becomes Student.

The return type is Collector<T, ?, Integer>, which declares three types of its own:

  • First comes the input, matching your stream elements
  • A wildcard hides the accumulator, an internal JDK detail you never name
  • Last is the finished result, an Integer

Finally, ToIntFunction<? super T> mapper is your extractor. It takes one object and returns a plain int. The ? super T part simply lets an extractor written for a parent class work on a stream of its children.

4.3 The Student Class

package com.javahandson.collectors.summing;

public class Student {

    int rollNumber;
    String name;
    int marks;

    public Student(int rollNumber, String name, int marks) {
        this.rollNumber = rollNumber;
        this.name = name;
        this.marks = marks;
    }

    public String getName() {
        return name;
    }

    public int getMarks() {
        return marks;
    }
}

4.4 Adding Up the Marks

package com.javahandson.collectors.summing;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class SummingIntDemo {
    public static void main(String[] args) {

        List<Student> studentList = Arrays.asList(
                new Student(101, "Suraj", 450),
                new Student(102, "Iqbal", 470),
                new Student(103, "Amar", 430),
                new Student(104, "Amit", 400),
                new Student(105, "Suchit", 380),
                new Student(106, "Kartik", 490));

        int totalMarks = studentList.stream()
                .collect(Collectors.summingInt(Student::getMarks));

        System.out.println("Total marks of students : " + totalMarks);
    }
}
// Output:
// Total marks of students : 2620

Check the arithmetic if you like. 450 plus 470 plus 430 plus 400 plus 380 plus 490 comes to 2620.

The collector touched each student once and never built an intermediate list. That is the same amount of work the hand-written loop does.

4.5 An Empty List Gives Zero

Run the same code over an empty list and nothing breaks.

List<Student> studentList = new ArrayList<>();

int totalMarks = studentList.stream()
        .collect(Collectors.summingInt(Student::getMarks));

System.out.println("Total marks of students : " + totalMarks);
// Output:
// Total marks of students : 0

No exception, no Optional, no null. Zero is the right answer for an empty total, and the collector just gives it to you.

This is a genuine advantage over some of its neighbours. A max or a min has no sensible answer for an empty stream, which is why those return an Optional instead.

5. The summingLong Method

Same collector, wider numbers. This is the one to reach for when totals get big.

5.1 The Syntax

public static <T> Collector<T, ?, Long>
        summingLong(ToLongFunction<? super T> mapper)

5.2 What Actually Changes

Set the two signatures side by side and only two words differ.

  • The mapper becomes ToLongFunction rather than ToIntFunction
  • Your result is a Long instead of an Integer
  • Everything else, right down to the empty-stream zero, behaves identically

Typical long fields include database ids, file sizes in bytes, epoch timestamps, and view counters.

5.3 It Accepts int Values Too

Here is the useful part. A ToLongFunction happily accepts a getter that returns an int, because Java widens int to long automatically.

// getMarks() returns int, yet summingLong accepts it
long totalMarks = studentList.stream()
        .collect(Collectors.summingLong(Student::getMarks));

System.out.println(totalMarks);
// Output:
// 2620

So you can keep your int field and still get a long total. That single swap removes any chance of overflow, and it costs you nothing.

Remember this trick. It is the cleanest fix for the problem section 7 is about to describe.

6. The summingDouble Method

The third variant handles anything with a decimal point: prices, rates, weights, and percentages.

6.1 The Syntax

public static <T> Collector<T, ?, Double>
        summingDouble(ToDoubleFunction<? super T> mapper)

It accepts int and long getters as well, since Java widens both to double. The shape should feel familiar by now.

6.2 Adding Up Prices

package com.javahandson.collectors.summing;

public class Item {

    private final String name;
    private final String category;
    private final double price;

    public Item(String name, String category, double price) {
        this.name = name;
        this.category = category;
        this.price = price;
    }

    public String getName()     { return name; }
    public String getCategory() { return category; }
    public double getPrice()    { return price; }
}
package com.javahandson.collectors.summing;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class SummingDoubleDemo {
    public static void main(String[] args) {

        List<Item> items = Arrays.asList(
                new Item("Notebook", "Stationery", 120.50),
                new Item("Pen", "Stationery", 15.25),
                new Item("Bag", "Accessories", 899.00),
                new Item("Bottle", "Accessories", 249.75),
                new Item("Lamp", "Home", 515.50));

        double total = items.stream()
                .collect(Collectors.summingDouble(Item::getPrice));

        System.out.println("Cart total : " + total);
        System.out.printf("Formatted  : %.2f%n", total);
    }
}
// Output:
// Cart total : 1800.0
// Formatted  : 1800.00

Look at the two output lines. Printing the raw double gives 1800.0, because Java drops trailing zeros. A price on a screen wants printf or a DecimalFormat instead.

6.3 Compensated Summation and NaN

Adding many doubles loses precision. Each addition rounds off a tiny amount, and those crumbs pile up over thousands of values.

summingDouble pushes back with compensated summation. It tracks the error left behind by each addition and folds it in at the end, so the total drifts far less than a naive running += would.

It cannot work miracles, though. The javadoc warns that the result still depends on the order of the values, so two runs over differently sorted data can differ in the last digits.

One bad value defeats it outright. Feed in a single NaN and the entire total becomes NaN, with no partial recovery.

// Filter suspect values before they reach the collector
double safe = items.stream()
        .filter(item -> !Double.isNaN(item.getPrice()))
        .collect(Collectors.summingDouble(Item::getPrice));

7. The Overflow Problem

This section is the one to remember. It produces wrong numbers rather than exceptions, which makes it far more dangerous than a crash.

7.1 Why summingInt Wraps

An int stops at 2147483647. Add one more and it does not throw. It wraps around to the most negative value and keeps going.

Inside, summingInt accumulates into a plain int. So the moment your running total crosses that line, the answer turns negative and nothing warns you.

7.2 All Three Side by Side

package com.javahandson.collectors.summing;

public class LargeNumber {

    private final int number;

    public LargeNumber(int number) {
        this.number = number;
    }

    public int getNumber() {
        return number;
    }
}
package com.javahandson.collectors.summing;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class OverflowDemo {
    public static void main(String[] args) {

        List<LargeNumber> list = Arrays.asList(
                new LargeNumber(2147483647),   // Integer.MAX_VALUE
                new LargeNumber(10));

        int intSum = list.stream()
                .collect(Collectors.summingInt(LargeNumber::getNumber));

        long longSum = list.stream()
                .collect(Collectors.summingLong(LargeNumber::getNumber));

        double doubleSum = list.stream()
                .collect(Collectors.summingDouble(LargeNumber::getNumber));

        System.out.println("summingInt    : " + intSum);
        System.out.println("summingLong   : " + longSum);
        System.out.println("summingDouble : " + doubleSum);
    }
}
// Output:
// summingInt    : -2147483639
// summingLong   : 2147483657
// summingDouble : 2.147483657E9

The first line is the whole lesson. Two positive numbers added together produced a negative result, and Java reported no error at all.

Work out where -2147483639 comes from. The true total is 2147483657, which sits 10 past the int ceiling. Wrapping subtracts the full int range and lands you deep in negative territory.

The other two lines handle it. A long has room to spare, and a double has range to spare. Java prints the double in scientific notation because the value passed ten million.

7.3 How to Choose Safely

A simple habit avoids the whole problem. Ask how large the total could get, not how large one element is.

  • Six students with marks under 500? summingInt is perfectly safe
  • A million rows of page views? Reach for summingLong instead
  • Unsure how big the data will grow? Default to summingLong and stop worrying
  • Already using a long or double field? The choice makes itself

Choosing summingLong for an int field costs nothing measurable. Choosing summingInt and overflowing costs you a wrong report that nobody spots for months.

8. Where Summing Collectors Really Shine

For a single total, a plain loop is honestly just as clear. The collectors earn their place when you nest them.

8.1 A Total per Group With groupingBy

Pass a summing collector as the downstream and every group gets its own total, from one pass over the data.

Map<String, Double> byCategory = items.stream()
        .collect(Collectors.groupingBy(Item::getCategory,
                Collectors.summingDouble(Item::getPrice)));

System.out.println("Stationery  : " + byCategory.get("Stationery"));
System.out.println("Accessories : " + byCategory.get("Accessories"));
System.out.println("Home        : " + byCategory.get("Home"));
// Output:
// Stationery  : 135.75
// Accessories : 1148.75
// Home        : 515.5

Try writing that with loops. You would need a map, a lookup, a null check, and an accumulate step, all inside the loop body.

Stationery adds 120.50 and 15.25 to reach 135.75. Accessories adds 899.00 and 249.75 for 1148.75. Home holds one item, so it prints 515.5 with the trailing zero dropped. Our guide on grouping in Java 8 covers the classifier side.

8.2 Two Totals With partitioningBy

When the split is a plain yes or no, partitioningBy reads better and guarantees both keys exist.

Map<Boolean, Double> byPrice = items.stream()
        .collect(Collectors.partitioningBy(
                item -> item.getPrice() >= 250,
                Collectors.summingDouble(Item::getPrice)));

System.out.println("Premium : " + byPrice.get(true));
System.out.println("Everyday: " + byPrice.get(false));
// Output:
// Premium : 1414.5
// Everyday: 385.5

The Bag at 899.00 and the Lamp at 515.50 clear the 250 line, giving 1414.5. Everything else totals 385.5. Note that the Bottle at 249.75 misses the cut by a quarter of a rupee.

Because partitioningBy always fills both keys, neither lookup can return null. Our article on partitioning in Java 8 explains why that matters.

8.3 Ranking Groups by Their Total

A map of totals is half a report. Usually you also want them ordered, biggest first.

byCategory.entrySet().stream()
        .sorted(Map.Entry.<String, Double>comparingByValue().reversed())
        .forEach(entry -> System.out.printf("%-12s %.2f%n",
                entry.getKey(), entry.getValue()));
// Output:
// Accessories  1148.75
// Home         515.50
// Stationery   135.75

The comparingByValue helper sorts on the total, and reversed flips it to descending. Swap in comparingByKey to sort alphabetically instead.

9. Alternatives Worth Knowing

The summing collectors are not the only way to total a field. Three alternatives come up constantly.

9.1 mapToInt and sum

Primitive streams carry their own sum() method. Map first, then add.

// Route A: the collector, returns Integer
int viaCollector = studentList.stream()
        .collect(Collectors.summingInt(Student::getMarks));

// Route B: the primitive stream, returns int
int viaStream = studentList.stream()
        .mapToInt(Student::getMarks)
        .sum();

// Both print 2620

Route B is shorter and skips the boxing, so prefer it for a standalone total. Route A wins the moment you need to nest the total inside groupingBy, because only a Collector fits that slot.

9.2 summarizingInt for More Than a Total

Needing the total and the average is common. Running two collectors means two passes, so use one summarizing collector instead.

IntSummaryStatistics stats = studentList.stream()
        .collect(Collectors.summarizingInt(Student::getMarks));

System.out.println(stats.getSum());     // 2620  (a long, not an int)
System.out.println(stats.getAverage()); // 436.6666666666667
System.out.println(stats.getMax());     // 490

One extra benefit hides in there. The getSum() method returns a long, so a summarizing collector cannot overflow the way summingInt can. Our guide on Java 8 summarizing methods covers the family in full.

9.3 reducing for BigDecimal

There is no summingBigDecimal, and money really should not live in a double. The reducing collector fills that gap.

// A plain total
BigDecimal total = invoices.stream()
        .map(Invoice::getAmount)
        .reduce(BigDecimal.ZERO, BigDecimal::add);

// The same thing as a downstream collector
Map<String, BigDecimal> byClient = invoices.stream()
        .collect(Collectors.groupingBy(Invoice::getClient,
                Collectors.reducing(BigDecimal.ZERO,
                                    Invoice::getAmount,
                                    BigDecimal::add)));

The three arguments read as a sentence: start at zero, pull this field out, and combine two values this way. Our article on the reduce method goes deeper.

9.4 The Alternatives Table

Approach Returns Boxes? Best for
Collectors.summingInt Integer Yes Totals inside groupingBy
mapToInt().sum() int No A standalone total
Collectors.summarizingInt IntSummaryStatistics No Two or more figures
Collectors.reducing Your own type n/a BigDecimal and custom types

10. Common Mistakes and Pitfalls

Six mistakes account for most of the summing bugs we meet in code reviews.

10.1 Unboxing a null From a Map

Remember that summing collectors return wrappers. Combine that with groupingBy, which omits keys that matched nothing, and you get a classic crash.

Map<String, Double> byCategory = items.stream()
        .collect(Collectors.groupingBy(Item::getCategory,
                Collectors.summingDouble(Item::getPrice)));

// No Books category exists, so get returns null, and unboxing it throws
double books = byCategory.get("Books");                  // NullPointerException

// Safe
double safeBooks = byCategory.getOrDefault("Books", 0.0);   // 0.0

The exception points at an innocent-looking assignment, which makes it confusing to debug. Use getOrDefault whenever the key might be missing.

10.2 Ignoring int Overflow

Section 7 covered this, and it deserves the repeat because it ships so quietly. Test data is small, so the bug never appears until real volumes arrive.

When in doubt, use summingLong. The cost is nothing and the protection is total.

10.3 Using double for Money

A double cannot hold every decimal exactly. Add 0.1 ten times and you do not land on 1.0, and those gaps show up on an invoice.

Compensated summation reduces the drift but never removes it. For anything a customer pays, use BigDecimal with reducing, or store paise and cents as a long and use summingLong.

10.4 Reusing a Consumed Stream

Stream<Student> stream = studentList.stream();

int marks = stream.collect(Collectors.summingInt(Student::getMarks));
// IllegalStateException: stream has already been operated upon or closed
int again = stream.collect(Collectors.summingInt(Student::getMarks));

A stream works exactly once. Call studentList.stream() freshly each time, since the source list itself stays reusable.

10.5 A null Element in the Stream

The collector never produces a null total. Your extractor can still explode, though, if an element itself is null.

// Throws NullPointerException inside getMarks()
list.stream().collect(Collectors.summingInt(Student::getMarks));

// Filter first
list.stream()
    .filter(Objects::nonNull)
    .collect(Collectors.summingInt(Student::getMarks));

10.6 Summing When You Need More

Chaining three separate collectors for a total, a count, and an average walks the data three times.

One summarizingInt gives you all five figures in a single pass. Reach for the summing collectors only when the total is genuinely all you want.

11. A Practical Walkthrough

Let us build one small report that uses two variants together.

11.1 The Problem

We have the lines of a shopping cart. Each line carries a category, a quantity, and an amount. The report needs:

  • How many lines the cart holds
  • The total number of units across every line
  • The order value, formatted as money
  • Units and value broken down per category

Quantities are whole numbers and money has decimals, so this needs summingInt and summingDouble together.

11.2 The Code

package com.javahandson.collectors.summing;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class CartReport {

    static class Line {
        private final String category;
        private final int quantity;
        private final double amount;

        Line(String category, int quantity, double amount) {
            this.category = category;
            this.quantity = quantity;
            this.amount = amount;
        }

        public String getCategory() { return category; }
        public int getQuantity()    { return quantity; }
        public double getAmount()   { return amount; }
    }

    public static void main(String[] args) {

        List<Line> lines = Arrays.asList(
                new Line("Stationery",  3, 135.75),
                new Line("Accessories", 1, 899.00),
                new Line("Accessories", 2, 249.75),
                new Line("Home",        1, 515.50),
                new Line("Stationery",  5,  76.25));

        long totalUnits = lines.stream()
                .collect(Collectors.summingLong(Line::getQuantity));

        double orderValue = lines.stream()
                .collect(Collectors.summingDouble(Line::getAmount));

        Map<String, Integer> unitsByCategory = lines.stream()
                .collect(Collectors.groupingBy(Line::getCategory,
                        Collectors.summingInt(Line::getQuantity)));

        Map<String, Double> valueByCategory = lines.stream()
                .collect(Collectors.groupingBy(Line::getCategory,
                        Collectors.summingDouble(Line::getAmount)));

        System.out.println("Lines       : " + lines.size());
        System.out.println("Total units : " + totalUnits);
        System.out.printf("Order value : %.2f%n", orderValue);

        for (String category : Arrays.asList("Stationery", "Accessories", "Home")) {
            System.out.println(category
                    + " : qty " + unitsByCategory.getOrDefault(category, 0)
                    + ", " + String.format("%.2f",
                            valueByCategory.getOrDefault(category, 0.0)));
        }
    }
}
// Output:
// Lines       : 5
// Total units : 12
// Order value : 1876.25
// Stationery : qty 8, 212.00
// Accessories : qty 3, 1148.75
// Home : qty 1, 515.50

11.3 Reading the Report

Check the totals against the data. Quantities 3, 1, 2, 1, and 5 add up to 12. The amounts come to 1876.25, and the three category values of 212.00, 1148.75, and 515.50 add back to the same figure.

Three habits from earlier sections appear in this code. Quantities use summingLong even though the field is an int, so a large cart can never overflow.

Every map lookup goes through getOrDefault, so a missing category returns a zero rather than throwing on unboxing. And String.format handles the money, because the raw double would print 212.0 instead of 212.00.

Swap any one of those and the report either crashes or looks wrong to a customer.

12. Interview Questions

Q: What is the summing method in Collectors API?

A: It is a family of three collectors in java.util.stream.Collectors that add up one numeric property across a stream of objects. You pass an extractor such as Student::getMarks, and the collector returns the total of that field.

Q: What are the three summing collectors in Java 8?

A: summingInt takes a ToIntFunction and returns Integer, summingLong takes a ToLongFunction and returns Long, and summingDouble takes a ToDoubleFunction and returns Double. Java 8 shipped all three, and their signatures have not changed since.

Q: What does summingInt return for an empty stream?

A: It returns 0, not null and not an Optional. summingLong also returns 0, and summingDouble returns 0.0. That makes them safer than max or min, which have no sensible answer for an empty stream and hand back an Optional instead.

Q: Why does summingInt return Integer instead of int?

A: A Collector must produce an object, because Java generics cannot hold a primitive type. Assigning the result to an int still works, since Java unboxes automatically. The wrapper only causes trouble when a map lookup returns null and unboxing throws a NullPointerException.

Q: What happens when summingInt overflows?

A: It wraps silently and gives a wrong answer, with no exception. Adding 10 to Integer.MAX_VALUE returns -2147483639. Use summingLong instead, which accepts an int getter through automatic widening and has room for a far larger total.

Q: What is the difference between Collectors.summingInt and IntStream.sum?

A: Both produce the same total in one pass. mapToInt(…).sum() returns a primitive int and skips the boxing, so it reads better for a standalone total. Collectors.summingInt is the only option when you need the total as a downstream collector inside groupingBy or partitioningBy.

Q: Can I use summingLong on an int property?

A: Yes. A ToLongFunction accepts a getter returning an int, because Java widens int to long automatically. This is the simplest way to keep an int field while getting a total that cannot overflow. The same widening lets summingDouble accept int and long getters.

Q: How do I get a total per group in Java 8?

A: Pass a summing collector as the downstream argument to groupingBy. For example groupingBy(Item::getCategory, summingDouble(Item::getPrice)) returns a Map of category to total. Use partitioningBy instead when the split is a simple yes or no.

Q: What is the difference between summingInt and summarizingInt?

A: summingInt gives you only the total, as an Integer that can overflow. summarizingInt gives you count, sum, min, max, and average in one IntSummaryStatistics object, and its sum is a long. Use summingInt when the total is all you need.

Q: Should I use summingDouble for money?

A: Not for amounts a customer pays. A double cannot represent every decimal exactly, and the errors accumulate. Use BigDecimal with Collectors.reducing(BigDecimal.ZERO, Invoice::getAmount, BigDecimal::add), or store the smallest unit such as paise as a long and use summingLong.

Q: Why does map.get() throw NullPointerException after groupingBy with summingInt?

A: groupingBy only creates a key when something matched it, so a missing key returns null. Because summingInt produces an Integer, assigning that null to an int unboxes it and throws. Use getOrDefault(key, 0) instead.

13. Conclusion

Let us wrap up what we covered. The summing collectors add one numeric property across a stream, and Java gives you three of them, one per numeric type.

All three return wrapper objects rather than primitives, and all three answer an empty stream with a clean zero. No Optional, no null, no special case in your code.

Watch the overflow. A summingInt total wraps silently once it passes 2147483647, and summingLong costs nothing while removing that risk entirely. It even accepts your existing int getter.

Keep summingDouble away from real money. Reach for BigDecimal with reducing, or count in paise with a long.

Above all, remember where these collectors beat a loop. Nested inside groupingBy or partitioningBy, they turn a page of map handling into one readable line.

Further Reading

Leave a Comment