成绩管理系统首选ArrayList存学生数据,因其随机访问快、按序遍历方便;按学号查改需额外用HashMap索引;去重统计用TreeSet;避免重复学号应维护HashSet记录已用ID;成绩计算须用Integer处理null并过滤;导出中文乱码需统一UTF-8编码。

成绩管理系统该用哪个集合存学生数据
直接用 ArrayList 最稳妥。学生数量不确定、需要按录入顺序遍历、偶尔查某位学生(比如学号),ArrayList 的随机访问快(get(int) 是 O(1)),增删末尾也快,比 LinkedList 更适合这个场景。
别用 HashSet ——除非你重写了 equals() 和 hashCode(),否则两个内容相同的学生对象会被当成不同对象存进去,查重、修改都会出错。如果真要按学号快速查找,用 HashMap,key 是学号字符串,这样 get("2023001") 就是 O(1) 查询。
- 学生列表展示、批量导出 → 用
ArrayList - 按学号实时查/改单个学生 → 补一个
HashMap做索引(不替代主列表) - 成绩去重统计(比如“哪些分数出现过”)→ 用
TreeSet自动排序去重
添加学生时怎么避免重复学号
不能只靠 ArrayList.contains(),它默认比较引用,得自己写逻辑。最简方式是在添加前遍历检查:
public boolean addStudent(Student stu) {
for (Student s : studentList) {
if (s.getId().equals(stu.getId())) {
return false; // 学号已存在
}
}
studentList.add(stu);
return true;
}
更高效的做法是维护一个 HashSet 专门存已用学号:
立即学习“Java免费学习笔记(深入)”;
- 初始化时:
SetusedIds = new HashSet(); - 添加前:
if (usedIds.contains(stu.getId())) return false; - 添加成功后:
usedIds.add(stu.getId());
注意:删除学生时,必须同步从 usedIds 中移除对应学号,否则内存泄漏+逻辑错误。
计算班级平均分和最高分为什么结果不对
常见原因是成绩字段用了 int 类型但没处理空值或非法输入。比如学生对象里 score 是 int,默认值是 0,但“未录入成绩”和“考了 0 分”语义完全不同——全班平均分会因此被拉低。
改用 Integer 可以表达 null,再配合 Stream 过滤:
double avg = studentList.stream()
.mapToInt(s -> s.getScore() != null ? s.getScore() : 0)
.average()
.orElse(0.0);
但更严谨的是先过滤掉 null:
double avg = studentList.stream()
.filter(s -> s.getScore() != null)
.mapToInt(Student::getScore)
.average()
.orElse(Double.NaN);
- 用
Double.NaN表示“无有效成绩”,比返回 0 更能暴露数据问题 - 最高分同理,用
.mapToInt(...).max().orElse(-1),-1 代表无成绩 - 别在循环里手动累加再除,容易整数除法截断(
int / int = int)
导出成绩到控制台时中文乱码怎么办
不是集合的问题,是 System.out 输出流的编码和终端不匹配。Windows 命令行默认 GBK,而 Java 源文件通常是 UTF-8 编译的,导致中文显示为问号或方块。
临时解决:在运行程序前,把 CMD 切成 UTF-8 模式:chcp 65001;或者用 IDE 运行时,在运行配置里设置 VM options:-Dfile.encoding=UTF-8。
真正健壮的做法是避开控制台输出中文——改用写文件,明确指定编码:
try (PrintWriter w = new PrintWriter("scores.txt", "UTF-8")) {
for (Student s : studentList) {
w.println(s.getName() + "\t" + s.getScore());
}
}
集合本身不涉及编码,但任何涉及字符串输出的环节,都得确认源头(String)、管道(Writer/Stream)、终点(终端/文件)三者编码一致。这点容易忽略,一出问题就怀疑集合用错了。










