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

Stream API实现分组学生GPA计算报错:无法填充Map求助

问题:Stream处理分组学生GPA计算出错

我搞不懂自己的代码为啥跑不起来,Stream部分肯定有问题,没法把List的数据填充到Map里。我要计算每个学生的总GPA,最终结果是一个嵌套Map——外层键是分组名,内层键是学生姓名,值是该学生的总GPA。

原代码

class Student4 {

    String name;
    Subject4[] subjects;

    public Student4(String name, Subject4[] subjects) {
        this.name = name;
        this.subjects = subjects;
    }

    public static void main(String[] args) {

        Student4 s1 = new Student4("Name1", new Subject4[]{
                new Subject4("A", new Integer[]{4, 4, 4, 4, 5}), //21 -> 4.2
                new Subject4("B", new Integer[]{5, 5, 5, 5, 5}), //25 -> 5.0
                new Subject4("C", new Integer[]{4, 4, 4, 4, 5})  //21 -> 4.2
        });
        Student4 s2 = new Student4("Name2", new Subject4[]{
                new Subject4("A", new Integer[]{3, 3, 3, 4, 5}), //18 -> 3.6
                new Subject4("B", new Integer[]{5, 3, 3, 5, 5}), //21 -> 4.2
                new Subject4("C", new Integer[]{4, 3, 3, 4, 3})  //17 -> 3.4
        });
        Student4 s3 = new Student4("Name3", new Subject4[]{
                new Subject4("A", new Integer[]{5, 5, 5, 4, 5}), //24 -> 4.8
                new Subject4("B", new Integer[]{5, 5, 5, 4, 5}), //24 -> 4.8
                new Subject4("C", new Integer[]{5, 5, 5, 4, 5})  //24 -> 4.8
        });
        Student4 s4 = new Student4("Name4", new Subject4[]{
                new Subject4("A", new Integer[]{5, 5, 5, 4, 5}), //24 -> 4.8
                new Subject4("B", new Integer[]{5, 5, 5, 4, 5}), //24 -> 4.8
                new Subject4("C", new Integer[]{5, 5, 5, 4, 5})  //24 -> 4.8
        });

        Map<String, List<Student4>> group = new HashMap<>();
        group.put("group1", List.of(s1, s2));
        group.put("group2", List.of(s3, s4));

        Map<String, Map<String, Double>> averageByStudent = group.entrySet().stream()
                .collect(Collectors.toMap(entry -> entry.getKey(),
                        entry -> entry.getValue().stream()
                                .collect(Collectors.toMap(entry.getValue().stream()
                                                .map(z -> z.name),
                                        entry.getValue().stream()
                                                .flatMap(v -> Arrays.stream(v.subjects))
                                                .flatMap(w -> Arrays.stream(w.mark))
                                                .mapToDouble(Integer::doubleValue)
                                                .average().getAsDouble()
                                ))));
    }
}

class Subject4 {

    String name;
    Integer[] mark;

    public Subject4(String name, Integer[] mark) {
        this.name = name;
        this.mark = mark;
    }
}

错误分析

  1. 内层Collectors.toMap参数错误:你把整个分组的学生Stream直接传给keyMapper,不符合API要求——keyMapper应该是针对每个Student4对象的函数,返回该学生的姓名作为键。
  2. GPA计算逻辑错误:原代码把整个分组的所有学生成绩混在一起求平均,这不是单个学生的总GPA,应该针对每个学生单独计算其所有科目成绩的平均值。

修正后的代码

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

class Student4 {

    String name;
    Subject4[] subjects;

    public Student4(String name, Subject4[] subjects) {
        this.name = name;
        this.subjects = subjects;
    }

    // 计算当前学生的总GPA
    public double calculateTotalGPA() {
        return Arrays.stream(subjects)
                .flatMap(subject -> Arrays.stream(subject.mark))
                .mapToDouble(Integer::doubleValue)
                .average()
                .orElse(0.0); // 无成绩时返回0.0,避免空指针
    }

    public static void main(String[] args) {

        Student4 s1 = new Student4("Name1", new Subject4[]{
                new Subject4("A", new Integer[]{4, 4, 4, 4, 5}), //21 -> 4.2
                new Subject4("B", new Integer[]{5, 5, 5, 5, 5}), //25 -> 5.0
                new Subject4("C", new Integer[]{4, 4, 4, 4, 5})  //21 -> 4.2
        });
        Student4 s2 = new Student4("Name2", new Subject4[]{
                new Subject4("A", new Integer[]{3, 3, 3, 4, 5}), //18 -> 3.6
                new Subject4("B", new Integer[]{5, 3, 3, 5, 5}), //21 -> 4.2
                new Subject4("C", new Integer[]{4, 3, 3, 4, 3})  //17 -> 3.4
        });
        Student4 s3 = new Student4("Name3", new Subject4[]{
                new Subject4("A", new Integer[]{5, 5, 5, 4, 5}), //24 -> 4.8
                new Subject4("B", new Integer[]{5, 5, 5, 4, 5}), //24 -> 4.8
                new Subject4("C", new Integer[]{5, 5, 5, 4, 5})  //24 -> 4.8
        });
        Student4 s4 = new Student4("Name4", new Subject4[]{
                new Subject4("A", new Integer[]{5, 5, 5, 4, 5}), //24 -> 4.8
                new Subject4("B", new Integer[]{5, 5, 5, 4, 5}), //24 -> 4.8
                new Subject4("C", new Integer[]{5, 5, 5, 4, 5})  //24 -> 4.8
        });

        Map<String, List<Student4>> group = new HashMap<>();
        group.put("group1", List.of(s1, s2));
        group.put("group2", List.of(s3, s4));

        // 修正后的Stream处理逻辑
        Map<String, Map<String, Double>> averageByStudent = group.entrySet().stream()
                .collect(Collectors.toMap(
                        Map.Entry::getKey, // 外层Map的键:分组名
                        entry -> entry.getValue().stream()
                                .collect(Collectors.toMap(
                                        Student4::getName, // 内层Map的键:学生姓名
                                        Student4::calculateTotalGPA // 内层Map的值:学生总GPA
                                ))
                ));

        // 打印结果验证
        averageByStudent.forEach((groupName, studentGPAs) -> {
            System.out.println("分组:" + groupName);
            studentGPAs.forEach((name, gpa) -> System.out.println(name + " - " + gpa));
        });
    }

    // 封装字段访问
    public String getName() {
        return name;
    }
}

class Subject4 {

    String name;
    Integer[] mark;

    public Subject4(String name, Integer[] mark) {
        this.name = name;
        this.mark = mark;
    }
}

修正说明

  1. 新增calculateTotalGPA()方法:把单个学生的GPA计算逻辑封装起来,代码更清晰易维护。
  2. 修正Stream嵌套逻辑:外层处理分组,内层针对每个学生,用Student4::getName作为内层Map的键,Student4::calculateTotalGPA作为对应的值,完全匹配需求。
  3. 新增getName()方法:遵循封装原则,避免直接访问成员变量。
  4. 用orElse(0.0)处理空值:如果学生没有任何成绩,避免抛出NoSuchElementException。

内容的提问来源于stack exchange,提问作者R Zav

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 08:20:12