Java ATM模拟程序抛出IllegalStateException异常,求原因及修复方案
嘿,我来帮你拆解这个问题,一步步解决你的ATM程序异常问题:
问题分析与解决方案
1. 什么是IllegalStateException?
简单说,这是一种运行时异常,当你调用某个对象的方法,但这个对象当前的状态根本不允许执行这个操作时,就会抛出它。比如你现在的情况:Scanner已经被关闭了,你还想调用它的nextInt()方法读取输入,这就属于“对象状态不合法”,所以触发了这个异常。
2. 你的场景里异常产生的核心原因
看你的代码,问题出在finally块的位置:
你把input.close();放在了最内层的try-catch的finally里,而这个try-catch又嵌套在外层的do-while循环中。
- 第一次用户输入非数字触发
InputMismatchException时,catch块处理完异常,finally会强制执行,直接把Scanner关闭了。 - 但外层的
do-while循环还在继续跑,下一次循环再调用input.nextInt()的时候,Scanner已经是关闭状态了,自然就抛出了IllegalStateException。
另外还有个隐藏问题:触发InputMismatchException后,用户输入的无效内容(比如字母)还留在Scanner的输入缓冲区里,如果不清理,下次循环会一直读取这个无效内容,导致无限抛出异常。
3. 具体修复步骤
(1)把Scanner关闭移到循环外面
Scanner是整个程序用来读取输入的工具,应该等到整个程序结束(也就是外层循环退出后)再关闭,而不是每次循环结束就关闭。把input.close();从finally块里移到最外层do-while循环的外面。
(2)在catch块里清理输入缓冲区
捕获InputMismatchException后,调用input.nextLine()把缓冲区里的无效输入清空,这样下次循环才能正常读取新的用户输入。
修改后的核心代码示例
public static void main(String[] args) { Scanner input = new Scanner(System.in); boolean infiniteLoop = true; boolean invalidInput; int id; Account[] accountArray = new Account[10]; for (int i = 0; i < accountArray.length; i++) { accountArray[i] = new Account(i, 100); } do { try { // 原有的内部ID验证循环 do { invalidInput = false; System.out.print("Enter an id: "); id = input.nextInt(); if (id < 0 || id > 9) { System.out.println("Try again. Id not registered in system. Please enter an id between 0 and 9 (inclusive)."); invalidInput = true; input.nextLine(); } } while (invalidInput); // 原有的主菜单循环 boolean exit; do { exit = false; boolean notAnOption; int choice; do { notAnOption = false; System.out.print("\nMain Menu\n1: check balance\n2: withdraw\n3: deposit\n4: exit\nEnter a choice: "); choice = input.nextInt(); if (choice < 1 || choice > 4) { System.out.println("Sorry, " + choice + " is not an option. Please try again and enter a number between 1 and 4 (inclusive)."); notAnOption = true; } } while(notAnOption); switch (choice) { case 1: System.out.println("The balance for your account is $" + accountArray[id].getBalance()); break; case 2: boolean withdrawFlag; do { System.out.print("Enter the amount you would like to withdraw: "); // 建议改成nextDouble支持小数金额 double withdrawAmount = input.nextDouble(); if (withdrawAmount > accountArray[id].getBalance()) { System.out.println("Sorry, you only have an account balance of $" + accountArray[id].getBalance() + ". Please try again and enter a number at or below this amount."); withdrawFlag = true; } else { accountArray[id].withdraw(withdrawAmount); System.out.println("Thank you. Your withdraw has been completed."); withdrawFlag = false; } } while (withdrawFlag); break; case 3: System.out.print("Enter the amount you would like to deposit: "); // 建议改成nextDouble支持小数金额 double depositAmount = input.nextDouble(); accountArray[id].deposit(depositAmount); System.out.println("Thank you. You have successfully deposited $" + depositAmount + " into your account."); break; case 4: System.out.println("returning to the login screen...\n"); exit = true; break; } } while (!exit); } catch (InputMismatchException ex) { System.out.println("Sorry, invalid input. Please enter a number, no letters or symbols."); // 清理缓冲区的无效输入 input.nextLine(); } // 移除原来的finally块 } while (infiniteLoop); // 程序结束前才关闭Scanner input.close(); }
额外优化建议
- 你的
infiniteLoop变量一直是true,程序会无限运行,建议可以加个退出逻辑,比如在ID输入环节输入-1时,把infiniteLoop设为false,让程序正常退出。 - 目前你用
input.nextInt()处理存款和取款金额,只能接受整数,改成input.nextDouble()可以支持小数金额,更符合ATM的实际场景。
内容的提问来源于stack exchange,提问作者Ryan Foster
相关产品推荐
相关产品推荐

