gpa gpa -4 years ago 177
Java Question

Java 8 Lambda Collectors.summingLong multiple columns?

I have POJO definition as follows:

class EmployeeDetails{
private String deptName;
private Double salary;
private Double bonus;
...
}


Currently, i have lambda expression for Group By
'deptName'
as :

$set.stream().collect(Collectors.groupingBy(EmployeeDetails::getDeptName,
Collectors.summingLong(EmployeeDetails::getSalary));


Question Is it possible to Sum more than one column? I need to compute sum on both fields
salary and bonus
in one expression instead of multiple times?

SQL representation would be:

SELECT deptName,SUM(salary),SUM(bonus)
FROM TABLE_EMP
GROUP BY deptName;

Answer Source

You need to create an additional class that will hold your 2 summarised numbers (salary and bonus). And a custom collector.

Let's say you have

private static final class Summary {
    private double salarySum;
    private double bonusSum;

    public Summary() {
        this.salarySum = 0;
        this.bonusSum = 0;
    }

    @Override
    public String toString() {
        return "Summary{" +
                "salarySum=" + salarySum +
                ", bonusSum=" + bonusSum +
                '}';
    }
}

for holding sums. Then you need a collector like this:

private static class EmployeeDetailsSummaryCollector implements Collector<EmployeeDetails, Summary, Summary> {
    @Override
    public Supplier<Summary> supplier() {
        return Summary::new;
    }

    @Override
    public BiConsumer<Summary, EmployeeDetails> accumulator() {
        return (summary, employeeDetails) -> {
            summary.salarySum += employeeDetails.salary;
            summary.bonusSum += employeeDetails.bonus;
        };
    }

    @Override
    public BinaryOperator<Summary> combiner() {
        return (summary, summary1) -> {
            summary.salarySum += summary1.salarySum;
            summary.bonusSum += summary1.bonusSum;
            return summary;
        };
    }

    @Override
    public Function<Summary, Summary> finisher() {
        return Function.identity();
    }

    @Override
    public Set<Characteristics> characteristics() {
        return EnumSet.of(IDENTITY_FINISH);
    }
}

With these classes you can collect your results like

final List<EmployeeDetails> employees = asList(
        new EmployeeDetails(/* deptName */"A", /* salary */ 100d, /* bonus */ 20d),
        new EmployeeDetails("A", 150d, 10d),
        new EmployeeDetails("B", 80d, 5d),
        new EmployeeDetails("C", 100d, 20d)
);

final Collector<EmployeeDetails, Summary, Summary> collector = new EmployeeDetailsSummaryCollector();
final Map<String, Summary> map = employees.stream()
        .collect(Collectors.groupingBy(o -> o.deptName, collector));
System.out.println("map = " + map);

Which prints this:

map = {A=[salary=250.0, bonus=30.0], B=[salary=80.0, bonus=5.0], C=[salary=100.0, bonus=20.0]}
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download