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
相关产品推荐
相关产品推荐

