Java读取txt学生名册实现姓名ID互查及异常处理问题咨询
现有实现的问题
你的当前代码可以跑通基础场景,但存在不少边界隐患和不符合开发规范的点:
- 匹配逻辑不可靠:使用
line.contains()做模糊匹配会出现子串误匹配问题,比如搜索Rea会错误命中Reagan的记录;用replace做内容截取也有风险,要是ID中刚好包含「姓名+空格」的子串,会导致返回结果错误,同时如果分隔符是多个空格、制表符,替换逻辑会直接失效。 - Scanner资源不可复用:文件对应的Scanner游标是单向的,遍历一次后就走到了文件末尾,如果你后续要做多次查询,第二次调用查询方法会直接抛异常,扩展性为0。
- 异常使用不规范:方法签名直接抛出
Exception基类属于不好的实践,过于宽泛的异常声明会让调用方无法预判具体故障类型,你可以自定义业务异常,或者直接用JDK内置的NoSuchElementException这类更明确的异常类型。 - 资源泄漏风险:你把文件流的
close()方法放在了try块内部,如果查询过程中抛出异常,close()不会被执行,会一直占用文件句柄造成资源泄漏。 - 代码冗余:
findID和findName两个方法的逻辑几乎完全一致,只是查询的目标字段不同,重复代码不利于后续维护。
优化方案
最核心的优化点是预加载全量数据到内存映射表,不用每次查询都遍历文件,同时解决上面的所有问题:
- 程序启动时一次性读取全量名册数据,分别存入
HashMap<String, String>类型的nameToId和idToName两个映射表,后续查询直接走O(1)的哈希表查询,性能远高于每次遍历文件。 - 每行数据用
split("\\s+", 2)按空白字符分割成两部分,严格区分姓名和ID,避免模糊匹配的问题。 - 使用Java 7+提供的try-with-resources语法自动管理文件流,不需要手动写close逻辑,彻底避免资源泄漏。
- 抽离公共的文件加载逻辑,消除重复代码。
优化后代码示例
package chapter11; import java.io.FileInputStream; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.Scanner; import java.util.NoSuchElementException; public class LabProgram { private static final Map<String, String> nameToId = new HashMap<>(); private static final Map<String, String> idToName = new HashMap<>(); // 预加载名册数据 private static void loadRoster(String fileName) throws IOException { try (FileInputStream fis = new FileInputStream(fileName); Scanner scanner = new Scanner(fis)) { while (scanner.hasNextLine()) { String line = scanner.nextLine().trim(); if (line.isEmpty()) continue; // 跳过空行 String[] parts = line.split("\\s+", 2); if (parts.length == 2) { nameToId.put(parts[0], parts[1]); idToName.put(parts[1], parts[0]); } } } } public static String findID(String studentName) { String id = nameToId.get(studentName); if (id == null) { throw new NoSuchElementException("Student ID not found for " + studentName); } return id; } public static String findName(String studentID) { String name = idToName.get(studentID); if (name == null) { throw new NoSuchElementException("Student name not found for " + studentID); } return name; } public static void main(String[] args) { Scanner scnr = new Scanner(System.in); try { // 读取文件名并预加载数据 String studentInfoFileName = scnr.next(); loadRoster(studentInfoFileName); // 读取查询选项 int userChoice = scnr.nextInt(); if (userChoice == 0) { String studentName = scnr.next(); System.out.println(findID(studentName)); } else { String studentID = scnr.next(); System.out.println(findName(studentID)); } } catch (IOException e) { System.out.println("Failed to read roster file: " + e.getMessage()); } catch (NoSuchElementException e) { System.out.println(e.getMessage()); } } }
内容的提问来源于stack exchange,提问作者Jake
相关产品推荐
相关产品推荐

