应优先使用ArrayList存储数据,因其适合小规模本地练习;需定义StudentDao接口并用MemoryStudentDao实现,封装校验逻辑,确保id唯一、字段非空、操作有明确反馈。
不用急着写 Student 类或连数据库,先想清楚:你这个系统是练手还是真要跑起来?如果是本地小规模练习(比如课程作业),直接用 ArrayList 就够了。硬上 MySQL 或 SQLite 反而分散对 CRUD 逻辑的注意力。
关键点在于封装好增删改查接口,让底层存储可替换。比如定义一个 StudentDao 接口,先用内存实现类 MemoryStudentDao,后面再换成 JdbcStudentDao —— 这样代码结构清晰,也符合面向接口编程的习惯。
Student 类必须有 id(建议用 int 或 long,别用 String 模拟主键)private,配齐 getter/setter,
重写 equals() 和 hashCode()(IDE 可自动生成)Student 里塞业务逻辑,比如“计算平均分”应放在服务层,不是实体类职责很多初学者只管往 ArrayList 里 add(),结果重复添加相同学号、姓名为空、年龄填负数——运行时不报错,但数据就乱了。
真正该做的不是“能不能加”,而是“该不该加”。比如:
add() 前检查 student.getId() 是否已存在(遍历或用 Map 加速)update() 必须先 findById(),找不到就返回 null 或抛 IllegalArgumentException,不能静默失败if (student.getId()
这些判断不写进 DAO 层,就容易在 main 方法里堆满 if,后期根本没法维护。
Scanner 是新手最常翻车的地方:输完数字按回车,下一次 nextLine() 突然读到空字符串;输了个字母,nextInt() 直接抛 InputMismatchException,程序就崩了。
解决办法很简单,统一用 nextLine() 读所有输入,再手动转类型:
System.out.print("请输入学号:");
String idStr = scanner.nextLine().trim();
int id = Integer.parseInt(idStr); // 这里 try-catch 包住
更稳妥的做法是封装一个工具方法:
readInt(String prompt),内部循环直到输入合法数字Scanner
这不是 bug,是误解。很多人写:
list.remove(student); // 错!这是按对象引用删 // 正确做法是: int index = list.indexOf(student); // 依赖 equals() 实现 if (index != -1) list.remove(index);
但更推荐直接按 ID 删除:
for (int i = 0; i < list.size(); i++) {
if (list.get(i).getId() == id) {
list.remove(i);
return true;
}
}
或者用 Java 8 的 removeIf():
list.removeIf(s -> s.getId() == id);
注意:如果用了 LinkedList,removeIf 性能不如 ArrayList,但学生系统数据量小,差别可忽略。重点是别依赖 equals() 的默认实现(即引用比较),否则 indexOf() 永远返回 -1。
真正难的不是写完增删改查,而是让每一步操作都有明确反馈(比如“删除成功”还是“未找到该学号”)、错误不崩溃、输入不卡死、数据不重复。这些细节堆起来,才叫“能用的系统”。