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

Java 8实现ArrayList分组求和Student分数的异常排查与解决

问题解决:Java 8 实现Student列表分组求和

报错原因

你遇到的IllegalStateException: Duplicate key异常,是因为如果尝试用Collectors.toMap时未指定重复键合并函数,当同一键(比如id)对应多个Student对象时,默认逻辑会抛出该异常。你当前的代码用了groupingBy(Student::getName),这只能按名字分组得到列表,无法直接得到分数求和后的结果,和预期需求不匹配。

正确实现方案

方案1:使用Collectors.toMap(推荐)

通过toMap的三参数版本,指定分组键、值生成逻辑和重复键合并逻辑,最后将Map的值转为List:

public class Test {
    public static void main(String[] args) {
        List<Student> list = new ArrayList<>();
        list.add(new Student(1, "A", 10));
        list.add(new Student(1, "A", 20));
        list.add(new Student(1, "A", 10));
        list.add(new Student(1, "A", 30));
        list.add(new Student(2, "B", 40));
        list.add(new Student(2, "B", 50));

        List<Student> result = list.stream()
                .collect(Collectors.toMap(
                        Student::getId, // 以id作为分组键(同一id对应同一name)
                        s -> new Student(s.getId(), s.getName(), s.getMarks()), // 初始化新的Student对象
                        (existing, next) -> { // 合并逻辑:累加分数
                            existing.setMarks(existing.getMarks() + next.getMarks());
                            return existing;
                        }
                ))
                .values()
                .stream()
                .collect(Collectors.toList());

        System.out.println(result);
        // 输出:[Student(id=1, name=A, marks=70), Student(id=2, name=B, marks=90)]
    }
}

@Data
@AllArgsConstructor
@NoArgsConstructor
class Student {
    int id;
    String name;
    int marks;
}

方案2:使用groupingBy + reducing

先按id分组,再对每个组内的Student进行分数求和合并:

import java.util.Objects;

public class Test {
    public static void main(String[] args) {
        List<Student> list = new ArrayList<>();
        list.add(new Student(1, "A", 10));
        list.add(new Student(1, "A", 20));
        list.add(new Student(1, "A", 10));
        list.add(new Student(1, "A", 30));
        list.add(new Student(2, "B", 40));
        list.add(new Student(2, "B", 50));

        List<Student> result = list.stream()
                .collect(Collectors.groupingBy(
                        Student::getId,
                        Collectors.reducing(
                                null,
                                s -> new Student(s.getId(), s.getName(), s.getMarks()),
                                (s1, s2) -> {
                                    s1.setMarks(s1.getMarks() + s2.getMarks());
                                    return s1;
                                }
                        )
                ))
                .values()
                .stream()
                .filter(Objects::nonNull) // 过滤reducing产生的null值
                .collect(Collectors.toList());

        System.out.println(result);
    }
}

关键说明

  • 两种方案都基于Java 8 Stream API实现,优先推荐方案1,代码更简洁高效。
  • 分组键选择id是因为同一id对应唯一的name,确保分组逻辑符合需求。
  • 合并时创建新的Student对象,避免修改原列表中的对象,保证数据不可变性。

内容的提问来源于stack exchange,提问作者Aditya Rewari

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 16:01:12