

新闻资讯
行业动态签到记录用ArrayList按时间追加,但“某学生今日是否签到”查询必须用HashMap或HashSet加速;否则O(n)遍历在500人以上明显卡顿。
ArrayList 还是 HashMap 存储更合适直接说结论:签到记录本身用 ArrayList 按时间顺序追加,但查“某学生今天是否签到”必须靠 HashMap 或 HashSet 加速——否则每次都要遍历整个列表,O(n) 查询在 500 人以上就明显卡顿。
常见错误是只用一个 ArrayList 存所有记录,然后写 for (SignRecord r : records) if (r.getStudentId().equals(id) && isToday(r.getTime())) ...,上线后老师点“查看未签到名单”要等三秒。
SignRecord 类至少包含 studentId(String)、time(LocalDateTime)、status(如 "PRESENT" / "LATE")HashMap,key 是学号,value 是该生今日最新签到记录(支持补签覆盖)ArrayList 做归档,但实时查询不碰它FileNotFoundException 和乱码Java 默认用平台编码读文件,Windows 上是 GBK,Linux/macOS 是 UTF-8,而学生名单 CSV 几乎全是 UTF-8 且带中文。不显式指定编码,new Scanner(new File("students.csv")) 在不同机器上会读成一堆问号或抛异常。
正确做法是统一用 Files.newBufferedReader 并强制指定 StandardCharsets.UTF_8:
try (BufferedReader reader = Files.newBufferedReader(Paths.get("students.csv"), StandardCharsets.UTF_8)) {
String line;
while ((line = reader.readLine()) != null) {
String[] parts = line.split(",");
if (parts.length >= 2) {
students.add(new Student(parts[0].trim(), parts[1].trim()));
}
}
}
FileReader —— 它没有编码参数,永远走默认编码id,name,grade),记得 reader.readLine() 先调一次跳过getClass().getResource("/students.csv") 更稳new Date() 比较因为 new Date() 返回的是带毫秒精度的绝对时间,而“今天”是个日期概念。直接 record.getTime().getDate() == new Date().getDate() 会失败——Date.getDate() 是月份中的日(1–31),但已弃用,且忽略年月;更糟的是,如果签到时间是 2025-05-20T23:59:59,服务器本地时间刚过 0 点,比较就失效。
正确方式是用 LocalDate 做截断比较:
LocalDate today = LocalDate.now(); LocalDate recordDate = record.getTime().toLocalDateTime().toLocalDate(); boolean isToday = today.equals(recordDate);
SimpleDateFormat 解析再比字符串——慢且线程不安全String(如 "2025-05-20 08:23:15"),解析时务必捕获 DateTimeParseException
LocalDate.now(ZoneId.of("Asia/
Shanghai")) 显式指定学生姓名里有逗号(如 “张三,男”)或换行符(如备注栏含 \n),直接 String.join(",", fields) 会导致 CSV 格式错乱,Excel 打开后列偏移、行断裂。
必须按 RFC 4180 规范:字段含逗号、换行或双引号时,整个字段用双引号包裹,且内部双引号转义为两个双引号:
public static String escapeCsvField(String field) {
if (field == null) return "";
if (field.contains(",") || field.contains("\n") || field.contains("\"")) {
return "\"" + field.replace("\"", "\"\"") + "\"";
}
return field;
}
// 使用示例:
String line = String.join(",",
escapeCsvField(student.getId()),
escapeCsvField(student.getName()),
escapeCsvField("未签到")
);
replace("\"", "\"\"") 就够,replaceAll 反而容易误伤BufferedWriter 而非拼接字符串,避免 OOM"absent_20250520.csv",方便老师归档真正麻烦的不是功能实现,而是 CSV 字段内容不可控——你永远不知道教务系统导出的姓名里有没有隐藏的全角逗号或零宽空格。