Java中Collectors.groupingBy优化:单步获取各年级最高分学生
获取各年级总分最高学生的单步Stream优化方案
问题背景
需要从学生成绩数据中,按年级(standard)分组后提取每组中总分(totalMarks)最高的学生。当前实现用了两步Stream操作,希望优化为单步完成。
示例数据
{ "students": [ { "fullName": "Student 1", "standard": 10, "rollNumber": "1R", "house": "Red", "marks": { "maths": 90, "english": 90, "science": 80, "history": 90 }, "totalMarks": 350, "sports": [ { "sportName": "karate", "status": "purple-belt" }, { "sportName": "swimming", "status": "swimmer" }, { "sportName": "karate", "status": "green-belt" } ], "hobbies": [ "programming", "reading" ] }, { "fullName": "Student 2", "standard": 10, "rollNumber": "2R", "house": "Blue", "marks": { "maths": 90, "english": 90, "science": 90, "history": 90 }, "totalMarks": 360, "sports": [ { "sportName": "cricket", "status": "all-rounder" } ], "hobbies": [ "gaming" ] } ] }
现有实现代码
Map<Integer, List<Student>> map8 = reportCard.getStudents().stream().collect(Collectors.groupingBy(Student::getStandard)); map8.keySet().forEach(key -> map8.put(key, map8.get(key).stream().reduce((st1,st2) -> st1.getTotalMarks() > st2.getTotalMarks()? st1:st2).stream().toList())); map8.forEach((key, value) -> System.out.println(key + "-" + value));
优化后的单步实现
可以利用Collectors.groupingBy的重载方法,直接在分组时指定下游收集器完成最高分学生的提取,无需后续遍历修改Map。
方案1:返回Map<Integer, Student>(推荐,更简洁)
Map<Integer, Student> topStudentPerGrade = reportCard.getStudents().stream() .collect(Collectors.groupingBy( Student::getStandard, Collectors.collectingAndThen( Collectors.maxBy(Comparator.comparingInt(Student::getTotalMarks)), optStudent -> optStudent.orElse(null) // 空分组时返回null,可根据需求替换为默认学生对象 ) )); // 输出结果 topStudentPerGrade.forEach((grade, student) -> System.out.printf("年级%d: %s,总分%d%n", grade, student.getFullName(), student.getTotalMarks()) );
方案2:保留Map<Integer, List<Student>>结构
如果需要和原有代码的返回类型一致(每个年级对应一个含最高分学生的列表),可调整如下:
Map<Integer, List<Student>> topStudentListPerGrade = reportCard.getStudents().stream() .collect(Collectors.groupingBy( Student::getStandard, Collectors.collectingAndThen( Collectors.maxBy(Comparator.comparingInt(Student::getTotalMarks)), opt -> opt.map(Collections::singletonList).orElse(Collections.emptyList()) ) )); topStudentListPerGrade.forEach((key, value) -> System.out.println(key + "-" + value));
关键逻辑说明
Collectors.groupingBy(Student::getStandard):按年级完成分组。Collectors.maxBy(Comparator.comparingInt(Student::getTotalMarks)):在每个分组内部,通过比较totalMarks的数值,筛选出分数最高的学生,返回Optional<Student>(避免空分组时抛出异常)。Collectors.collectingAndThen(...):将Optional<Student>转换为最终需要的类型——要么直接提取学生对象,要么包装成单元素列表,同时处理空分组的边界情况。
内容的提问来源于stack exchange,提问作者astar
相关产品推荐
相关产品推荐

