You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java 8按自定义Student对象多属性分组并生成聚合对象列表

解决方案

原代码错误分析

  • AbstractMap.SimpleEntry仅支持两个参数的构造方法,无法传入三个字段作为分组键。
  • double是基本数据类型,没有add()方法,求和直接用+运算符即可。

方法一:使用Java 16+ 记录类作为分组键

Java 16引入的记录类会自动生成equals()和hashCode(),非常适合作为多字段分组键:

首先定义记录类:

record StudentKey(String name, int age, String city) {}

然后修改流处理代码:

List<Student> students = // 初始化列表

List<Student> res = new ArrayList<>(students.stream()
    .collect(Collectors.toMap(
        // 用记录类封装三个分组字段
        student -> new StudentKey(student.getName(), student.getAge(), student.getCity()),
        // 初始值为当前Student实例
        Function.identity(),
        // 合并逻辑:对salary和incentive求和,生成新Student
        (s1, s2) -> new Student(
            s1.getName(),
            s1.getAge(),
            s1.getCity(),
            s1.getSalary() + s2.getSalary(),
            s1.getIncentive() + s2.getIncentive()
        )
    ))
    .values());

方法二:自定义分组键类(兼容Java 8+)

如果使用Java 8,需要自定义包含三个字段的类,并重写equals()和hashCode()以保证分组逻辑正确:

import java.util.Objects;

class StudentKey {
    private String name;
    private int age;
    private String city;

    public StudentKey(String name, int age, String city) {
        this.name = name;
        this.age = age;
        this.city = city;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        StudentKey that = (StudentKey) o;
        return age == that.age && Objects.equals(name, that.name) && Objects.equals(city, that.city);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age, city);
    }
}

流处理代码与方法一完全一致。

方法三:分组+聚合的清晰写法

用groupingBy先分组,再通过reducing完成聚合,逻辑更直观:

List<Student> res = students.stream()
    .collect(Collectors.groupingBy(
        s -> new StudentKey(s.getName(), s.getAge(), s.getCity()),
        Collectors.collectingAndThen(
            Collectors.reducing(
                (s1, s2) -> new Student(
                    s1.getName(),
                    s1.getAge(),
                    s1.getCity(),
                    s1.getSalary() + s2.getSalary(),
                    s1.getIncentive() + s2.getIncentive()
                )
            ),
            Optional::get
        )
    ))
    .values()
    .stream()
    .collect(Collectors.toList());

reducing负责合并组内的Student实例,collectingAndThen处理聚合后的Optional结果(每组至少有一个元素,get()操作安全)。

验证结果

运行上述代码后,输入的6个Student会被正确分组求和,输出与示例完全一致:

Student("Raj",10,"Pune",30000,300)
Student("Raj",20,"Pune",10000,100)
Student("Ram",30,"Pune",40000,400)
Student("Seema",10,"Pune",10000,100)

内容的提问来源于stack exchange,提问作者prachi Kadam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 10:50:46