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

ATM程序持续抛出NoSuchElementException异常,求解决方案

简易ATM程序NoSuchElementException问题解决指南

问题背景

开发简易ATM辅助程序时,菜单循环逻辑(显示菜单→等待输入→执行任务→再次显示菜单)持续抛出NoSuchElementException,且要求不在main方法中直接创建Scanner实例。

异常根源

  1. System.in流被提前关闭:PasswordController.control()方法中调用了sc1.close(),直接关闭了全局唯一的System.in输入流。后续Operator类中创建的Scanner尝试读取已关闭的流,必然触发异常。
  2. 多余的nextLine()调用:两处代码都存在无意义的重复读取:
    • PasswordController中读取密码后额外调用sc1.nextLine(),会跳过用户一次输入,甚至在无输入时触发异常。
    • Operator中显示菜单后先调用sc.nextLine()再读取选项,导致用户的第一次输入被跳过。
  3. 重复创建Scanner实例:Operator的循环中每次都新建Scanner,既浪费资源,也增加了出错概率。

解决方案

核心规则

  • 全局复用同一个Scanner实例,绝对不要关闭绑定System.in的Scanner(关闭后无法恢复输入流)。
  • 删除所有多余的nextLine()调用,保证输入读取逻辑和用户操作匹配。
  • 通过构造函数注入传递Scanner实例,避免在main中直接暴露Scanner。

修改后代码示例

1. 重构PasswordController类

public class PasswordController {
    private Account account;
    private MessageService message;
    private Scanner scanner;

    // 通过构造函数注入Scanner
    public PasswordController(Account account, MessageService message, Scanner scanner) {
        this.account = account;
        this.message = message;
        this.scanner = scanner;
    }

    public boolean control() {
        boolean result = false;
        int count = 0;           
        while(count < 3) {                                    
            System.out.println("Enter password");
            String password = scanner.nextLine();
            // 移除多余的nextLine()调用
            if (password.equals(account.getPassword())) {
                System.out.println("Password is correct.");
                result = true;
                count = 3;
            } else {
                message.badPassword();
                count++;
            }
        }
        if(!result) {
            System.out.println("3 wrong tries, card is now frozen. Please contact the bank");
        }
        // 禁止关闭scanner
        return result;
    }
}

2. 重构Operator类

public class Operator {
    private Account account;
    private Operations op;
    private Scanner scanner;

    // 通过构造函数注入Scanner
    public Operator(Account account, Operations op, Scanner scanner) {
        this.account = account;
        this.op = op;
        this.scanner = scanner;
    }

    // 修正方法名拼写错误:operationSellect → operationSelect
    public void operationSelect() {
        boolean keepRunning = true;
        
        while(keepRunning) {
            System.out.println("Enter the operation number you want to do: ");
            System.out.println("1 : Show Balance"); // 修正拼写错误:Ballance → Balance
            System.out.println("2 : Withdraw cash");
            System.out.println("3 : Deposit Money");
            System.out.println("4 : Exit System");
            System.out.println("");
            
            // 移除多余的nextLine()调用
            String option = scanner.nextLine();
            
            switch(option) {
                case "1":
                    op.showBalance(account);
                    break;
                case "2":
                    op.withdraw(account);
                    break;
                case "3":
                    op.deposit(account);
                    break;
                case "4":
                    keepRunning = false;
                    break;
                default:
                    System.out.println("Entered a wrong character, please enter again");
            }
        }
    }
}

3. 调整Main类实现依赖注入

public class Main {
    public static void main(String[] args) {
        // 创建全局唯一的Scanner实例
        Scanner scanner = new Scanner(System.in);
        
        Account account = new Account(1234, "1234", 3000, 2);
        Card card = new Card("123456","Cash");
        MessageService messageService = new MessageService();
        CardReader cardReader = new CardReader(account , card, messageService);
        // 注入Scanner到PasswordController
        PasswordController passwordController = new PasswordController(account, messageService, scanner);
        Operations operations = new Operations();
        // 注入Scanner到Operator
        Operator operator = new Operator(account, operations, scanner);
        
        ATM atm = new ATM(cardReader, passwordController, messageService, operations, operator, account, card);
        
        atm.start();
        
        // 程序结束时统一关闭Scanner(可选,JVM退出时会自动处理)
        scanner.close();
    }
}

额外提示

  • 永远不要关闭绑定System.in的Scanner,除非确认程序后续完全不需要读取控制台输入。
  • 所有需要读取输入的类都通过构造函数获取同一个Scanner实例,避免重复创建。
  • 代码中修正了几处拼写错误,提升了整体可读性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 01:22:14