Java 8 Lambda Collectors.summingLong多列?

gpa*_*gpa 8 java lambda java-8

我有POJO定义如下:

class EmployeeDetails{
 private String deptName;
 private Double salary;
 private Double bonus;
 ...
}
Run Code Online (Sandbox Code Playgroud)

目前,我有Group By的lambda表达式'deptName':

$set.stream().collect(Collectors.groupingBy(EmployeeDetails::getDeptName,
                                 Collectors.summingLong(EmployeeDetails::getSalary));
Run Code Online (Sandbox Code Playgroud)

问题是否可以汇总多个列?我需要在一个表达式中计算两个字段的总和salary and bonus而不是多次?

SQL表示将是:

SELECT deptName,SUM(salary),SUM(bonus)
FROM TABLE_EMP
GROUP BY deptName;
Run Code Online (Sandbox Code Playgroud)

esi*_*n88 6

您需要创建一个额外的类来保存您的2个汇总数字(工资和奖金).和定制收藏家.

让我们说你有

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 +
                '}';
    }
}
Run Code Online (Sandbox Code Playgroud)

持有金额.然后你需要一个像这样的收藏家:

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(Collector.Characteristics.IDENTITY_FINISH);
    }
}
Run Code Online (Sandbox Code Playgroud)

通过这些课程,您可以收集结果

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);
Run Code Online (Sandbox Code Playgroud)

打印这个:

map = {A=[salary=250.0, bonus=30.0], B=[salary=80.0, bonus=5.0], C=[salary=100.0, bonus=20.0]}
Run Code Online (Sandbox Code Playgroud)


Eug*_*ene 5

我知道你已经有了答案,但这是我的看法(我正在写,而另一个已发布)。Pairjava中已经有AbstractMap.SimpleEntry.

 System.out.println(Stream.of(new EmployeeDetails("first", 50d, 7d), new EmployeeDetails("first", 50d, 7d),
            new EmployeeDetails("second", 51d, 8d), new EmployeeDetails("second", 51d, 8d))
            .collect(Collectors.toMap(EmployeeDetails::getDeptName,
                    ed -> new AbstractMap.SimpleEntry<>(ed.getSalary(), ed.getBonus()), 
                    (left, right) -> {
                        double key = left.getKey() + right.getKey();
                        double value = left.getValue() + right.getValue();
                        return new AbstractMap.SimpleEntry<>(key, value);
                    }, HashMap::new)));
Run Code Online (Sandbox Code Playgroud)