Java Stream实现成绩评级 历史课缺考项计0分计算平均分
多课程规则兼容的成绩评级方法实现
问题核心
原defineMarks方法直接取taskResults中实际存在的分值计算平均分,仅适配任务成绩齐全的编程课场景,无法兼容历史课缺考任务计0分、按总任务数算平均分的要求。
两类课程的计分规则差异:
- 编程课:共3项任务,所有人成绩齐全,平均分 = 已完成任务总分 / 3
- 历史课:共4项任务,仅存3项已完成成绩,缺考1项计0分,平均分 = 已完成任务总分 / 4
改造实现
前置调整:给
CourseResult实体类增加totalTaskCount字段标记对应课程的总任务数,编程课实例该值设为3,历史课实例该值设为4,从数据源层面避免硬编码判断课程类型。如果无法修改实体,也可通过课程名称、任务名规则判断对应总任务数,核心计算逻辑不变。
import java.util.Map; import java.util.stream.Collectors; import java.util.stream.Stream; // 等级判定,可按需调整分数区间 private String mapToGrade(double averageScore) { if (averageScore >= 90) return "A"; if (averageScore >= 80) return "B"; if (averageScore >= 70) return "C"; if (averageScore >= 60) return "D"; return "F"; } public Map<Person, String> defineMarks(Stream<CourseResult> courseResultStream) { return courseResultStream.collect(Collectors.toMap( CourseResult::getPerson, result -> { // 统计已完成任务的总得分 int totalEarned = result.getTaskResults().values() .stream() .collect(Collectors.summarizingInt(Integer::intValue)) .getSum(); // 按课程总任务数计算平均分,缺考项0分无需额外补入集合,不影响总得分值 double avgScore = (double) totalEarned / result.getTotalTaskCount(); return mapToGrade(avgScore); } )); } // CourseResult 实体类参考 class CourseResult { private Person person; private Map<String, Integer> taskResults; private int totalTaskCount; // 构造器、getter方法省略 public Person getPerson() { return person; } public Map<String, Integer> getTaskResults() { return taskResults; } public int getTotalTaskCount() { return totalTaskCount; } }
逻辑说明
- 无需修改原有
programmingResults、historyResults的成绩生成逻辑,缺考任务的0分不需要手动插入taskResults集合:因为0分不会改变总得分值,只需要把平均分的除数从「实际存在的成绩条数」改成「课程总任务数」,就可以实现缺考计0的效果,代码更简洁没有额外开销。 - 编程课场景下
totalTaskCount值为3,和taskResults中的成绩条数一致,计算结果和原有逻辑完全一致,不会影响历史评级结果。 - 后续如果新增其他课程,只需要在生成
CourseResult实例时传入对应总任务数即可,不需要修改评级方法核心逻辑,扩展性更好。
内容的提问来源于stack exchange,提问作者fireballun
相关产品推荐
相关产品推荐

