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

Java收据总额计算程序InputMismatchException修复及优化咨询

收据计算程序问题修复方案

问题1:InputMismatchException 报错修复

这个异常本质是Scanner读取到的内容无法解析为Double类型,结合代码逻辑共有4个触发点,按优先级修复即可:

  • 流初始化顺序错误:在创建Scanner读取文件前,提前创建了开启追加模式的写入流,会触发文件锁,导致Scanner读取到空值或非法内容。写入流不要提前初始化,等需要写文件的时候再创建。
  • 写入模式配置错误:给FileWriter构造方法传入了第二个参数true开启追加写入模式,每次写新值都会拼在旧内容后面,多次运行后receipt.txt里的内容会变成类似0.0012.305.20的拼接字符串,自然无法解析为数字。
  • switch分支漏写break:case 0(查看总额)分支执行完后没有中断,会直接穿透执行case1的逻辑,此时Scanner已经把文件里唯一的数值读走,再次调用nextDouble()会读到空内容触发异常。
  • 输入解析逻辑错误:用户输入金额时用Integer.parseInt做类型转换,只要用户输入带小数的金额就会抛出格式错误,应该改为Double类型解析。

问题2:文件覆写更新逻辑与更优实现方案

正确的覆写更新流程

不要同时打开读、写流操作同一个文件,按以下顺序执行即可实现累加:

  1. 程序启动时先判断receipt.txt是否存在,不存在则创建文件并写入初始值0.00
  2. 仅创建读取流(Scanner)读取文件中存储的现有总额,读取完成后立刻关闭读取流,释放文件锁
  3. 处理用户选择:
    • 选择查看总额:直接格式化读取到的总额弹窗展示即可
    • 选择新增收据:获取用户输入的金额,和现有总额相加得到新的总金额
  4. 需要更新文件内容时,再创建FileWriter,第二个参数传入false(或直接省略该参数)开启覆写模式,把新的总金额格式化后写入文件,写完关闭写入流
  5. 每个switch分支末尾都加上break,避免逻辑穿透

更优实现方案

当前单值存储的方案能满足简单需求,但存在金额精度丢失、无对账记录、容错性差的问题,优化方向如下:

  • 流资源统一用try-with-resources语法创建,自动完成流关闭,避免资源泄漏和文件锁残留,不需要手动调用close()
  • 金额计算全部改用BigDecimal类型,彻底避免double/float类型的浮点数精度丢失问题(比如0.1+0.2计算结果偏差的问题),是金额类场景的标准实践
  • 存储逻辑优化:不要只存最终总额,改为每行存储一条收据记录(包含金额、记录时间、可选备注),每次启动时遍历所有记录累加得到总额,后续支持对账、删除错误记录的需求,容错性更高,单条记录损坏不会导致全量数据丢失
  • 增加异常兜底:读取文件内容失败时自动重置初始值,用户输入非数字金额时弹窗提示重新输入,避免程序直接崩溃

修复后可直接运行的参考代码

import javax.swing.JOptionPane;
import java.io.*;
import java.util.Scanner;
import java.text.DecimalFormat;
import java.math.BigDecimal;

class Receipts {
    public static void main(String[] args) throws IOException {
        DecimalFormat format = new DecimalFormat("0.00");
        File file = new File("receipt.txt");
        // 初始化文件,不存在则写入初始值0.00
        if (!file.exists()) {
            try (PrintWriter initWriter = new PrintWriter(new FileWriter(file))) {
                initWriter.print("0.00");
            }
        }

        // 先读取现有总额
        BigDecimal total = BigDecimal.ZERO;
        try (Scanner scan = new Scanner(file)) {
            if (scan.hasNext()) {
                String totalStr = scan.next().trim();
                try {
                    total = new BigDecimal(totalStr);
                } catch (NumberFormatException e) {
                    // 文件内容损坏时重置为0
                    total = BigDecimal.ZERO;
                }
            }
        }

        int choice = JOptionPane.showOptionDialog(null, "Hello. What would you like to do today?", "Receipts", JOptionPane.OK_CANCEL_OPTION, JOptionPane.INFORMATION_MESSAGE, null, new String[]{"See my total", "Add a receipt"}, "default");

        switch(choice) {
            case 0:  // 查看总额
                JOptionPane.showMessageDialog(null, "Your total so far is $" + format.format(total) + ".");
                break;
            case 1:  // 新增收据
                try {
                    String input = JOptionPane.showInputDialog("Enter the amount.");
                    BigDecimal receipt = new BigDecimal(input.trim());
                    BigDecimal newTotal = total.add(receipt);
                    // 覆写模式写入新总额
                    try (PrintWriter writer = new PrintWriter(new FileWriter(file, false))) {
                        writer.print(format.format(newTotal));
                    }
                    JOptionPane.showMessageDialog(null, "The amount has been added.");
                } catch (NumberFormatException e) {
                    JOptionPane.showMessageDialog(null, "Invalid amount input, please enter a valid number.");
                }
                break;
            default:
                JOptionPane.showMessageDialog(null, "Please input your selection.");
                break;
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 11:36:22