You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java图书馆系统GUI文件展示及NumberFormatException问题求助

解决你的图书馆系统两个问题:自动打开文件与NumberFormatException错误

一、先搞定NumberFormatException错误

从错误栈和你的代码来看,这个异常的根源很明确:你调用stringToLong()时传入了字符串"Book issued successfully"——而这个字符串正是你在Issue按钮点击后设置到NUM文本框的反馈信息。问题在于,为什么点击「显示已借书籍」的按钮会触发这个解析错误?

可能的原因及修复方案:

  1. 文本框引用搞混了
    检查你ActionListener里「Print details of books issued to member」的代码块,确认调用stringToLong()时传入的是cpr.getText()而不是NUM.getText()。如果不小心写成了stringToLong(NUM.getText()),就会把之前Issue按钮留下的提示文本当成数字解析,直接抛出异常。

    正确的代码应该是:

    long cprNum = stringToLong(cpr.getText()); // 确保这里是cpr文本框,不是NUM
    
  2. Issue按钮错误修改了cpr文本框
    检查Issue按钮的代码,确认你是给NUM文本框设置反馈,而不是cpr文本框。如果误写为cpr.setText("Book issued successfully"),那么用户后续输入CPR时,文本框里会残留这个字符串,导致解析失败。

    正确的Issue按钮代码:

    if (ITLib.issueBook(an, cpr))
        NUM.setText("Book issued successfully"); // 确认是NUM,不是cpr
    else
        NUM.setText("Book couldn't be issued. Try again later.");
    
  3. 给输入加一层验证
    为了避免类似问题,建议在调用stringToLong()前先校验输入是否为合法数字。可以给stringToLong()方法添加前置检查:

    private static long stringToLong(String stringObject) throws NumberFormatException {
        String trimmed = stringObject.trim();
        if (trimmed.isEmpty() || !trimmed.matches("\\d+")) {
            throw new NumberFormatException("Invalid number input: " + trimmed);
        }
        return Long.parseLong(trimmed);
    }
    

    然后在ActionListener中捕获异常,给用户友好提示:

    case "Print details of books issued to member": {
        try {
            long cprNum = stringToLong(cpr.getText());
            ITLib.printBooksIssued(cprNum);
        } catch (NumberFormatException e) {
            fName.setText("Error: Please enter a valid CPR number.");
        } catch (IOException e1){
            fName.setText("Error. Make sure CPR number is correct and try again.");
        }
    }
    

二、实现点击按钮自动打开文件的正确姿势

你已经用到了Desktop.getDesktop().open(file),但需要完善一些细节来确保稳定性:

优化后的printBooksIssued方法:

void printBooksIssued(long cpr) throws IOException {
    File file = new File("d:/work/test.txt");
    
    // 先保存原始的System.out,避免后续打印都被定向到文件
    PrintStream originalOut = System.out;
    try {
        System.setOut(new PrintStream(new FileOutputStream(file)));
        
        int memberIndex = searchMember(cpr);
        if (memberIndex == -1) {
            System.out.println("Member doesn't exist.");
        } else {
            // 直接用searchMember返回的索引获取会员,不用循环遍历
            LibMember m = membersList.get(memberIndex);
            System.out.println(Arrays.toString(m.getBooksIssued()));
        }
    } finally {
        // 必须恢复原始输出流,否则后续GUI的反馈会消失
        System.setOut(originalOut);
    }
    
    // 打开文件前先检查文件是否存在
    if (!file.exists()) {
        throw new IOException("File not found: " + file.getAbsolutePath());
    }
    
    try {
        Desktop.getDesktop().open(file);
    } catch (UnsupportedOperationException e) {
        // 处理无桌面环境的情况(比如服务器)
        System.err.println("Opening files is not supported on this system.");
    }
}

关键优化点:

  1. 恢复System.out:重定向输出流后一定要恢复,否则后续所有System.out.println()都会输出到文件,导致GUI中看不到其他操作反馈。
  2. 文件存在性检查:打开前确认文件已创建,避免抛出文件不存在的异常。
  3. 捕获UnsupportedOperationException:某些环境(如Linux无桌面环境、服务器)不支持Desktop类,需要捕获这个异常并给出提示。
  4. 优化会员查找逻辑:你已经有searchMember(cpr)方法返回索引,直接用这个索引获取会员即可,不用再循环遍历,提升效率。

额外小建议

尽量避免用System.setOut重定向输出到文件,直接用PrintWriter写入文件会更清晰,也不会影响全局输出:

try (PrintWriter writer = new PrintWriter(file)) {
    int memberIndex = searchMember(cpr);
    if (memberIndex == -1) {
        writer.println("Member doesn't exist.");
    } else {
        LibMember m = membersList.get(memberIndex);
        writer.println(Arrays.toString(m.getBooksIssued()));
    }
}

这种方式不需要恢复System.out,代码更简洁安全。

内容的提问来源于stack exchange,提问作者Ramsha Khalid

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 03:48:32