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

Java构造函数读取指定字符串时终止执行的优雅实现方案

优雅解决Java构造函数中读取输入初始化final变量并处理quit终止的问题

问题背景

在Game类构造函数中,需要通过System.in读取用户输入来初始化多个final成员变量;当用户输入"quit"时需终止程序,但禁止使用System.exit()或Runtime.exit()。现有两种方案存在明显缺陷:

  • 方案1:设置gameFinished标志,在每一步输入后检查该标志,代码冗余且不够优雅
  • 方案2:在输入方法中抛出异常并在构造函数捕获,但会导致final变量无法保证初始化,违反Java语法规则

最优解决方案:静态工厂方法+自定义受检异常

核心思路是将输入验证逻辑从构造函数中剥离,放到静态工厂方法中处理;遇到用户输入"quit"时抛出自定义受检异常,由调用层捕获并终止程序。构造函数仅负责接收已验证的参数,确保final变量全部初始化。

步骤1:定义自定义受检异常

创建QuitException用于标识用户触发的quit操作:

public class QuitException extends Exception {
    public QuitException() {
        super("用户请求终止游戏");
    }
}

步骤2:重构Game类

将构造函数改为私有,通过静态工厂方法createGame()处理输入逻辑,遇到quit直接抛异常:

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class Game {
    private final Scanner input;
    private final int playerCount;
    private final List<Player> players;
    private final int startGold;
    private final int winGold;
    private final int shuffleSeed;
    private int moveNumber;

    // 私有构造函数:仅接收已验证的参数,确保final变量全部初始化
    private Game(int playerCount, List<Player> players, int startGold, int winGold, int shuffleSeed) {
        this.input = new Scanner(System.in);
        this.playerCount = playerCount;
        this.players = players;
        this.startGold = startGold;
        this.winGold = winGold;
        this.shuffleSeed = shuffleSeed;
        this.moveNumber = 0;
        printLogo();
    }

    // 静态工厂方法:处理所有输入验证逻辑
    public static Game createGame() throws QuitException {
        Scanner input = new Scanner(System.in);
        printLogoStatic();

        int playerCount = getIntegerWithCondition(input, 1, "Question 1?");
        List<Player> players = getPlayerNames(input, playerCount);
        int startGold = getIntegerWithCondition(input, 0, "Question 2?");
        int winGold = getIntegerWithCondition(input, 1, "Question 3?");
        int shuffleSeed = getIntegerWithCondition(input, 0, "Question 4?");

        return new Game(playerCount, players, startGold, winGold, shuffleSeed);
    }

    private static int getIntegerWithCondition(Scanner input, int condition, String question) throws QuitException {
        System.out.println(question);
        boolean inputValid = false;
        int playerValue = 0;
        while (!inputValid) {
            String playerInput = input.nextLine();
            if (playerInput.equals("quit")) {
                throw new QuitException();
            }
            if (playerInput.matches("-*[0-9]+")) {
                try {
                    playerValue = Integer.parseInt(playerInput);
                    if (playerValue > condition) {
                        inputValid = true;
                    } else {
                        System.out.printf("Error: 输入必须大于%d!\n", condition);
                    }
                } catch (NumberFormatException e) {
                    System.out.println("Error: 数字格式无效!");
                }
            } else {
                System.out.println("Error: 输入不是有效数字!");
            }
        }
        return playerValue;
    }

    private static List<Player> getPlayerNames(Scanner input, int playerCount) throws QuitException {
        List<Player> players = new ArrayList<>();
        for (int i = 1; i <= playerCount; i++) {
            System.out.printf("请输入玩家%d的名字:\n", i);
            boolean inputValid = false;
            while (!inputValid) {
                String userInput = input.nextLine();
                if (userInput.equals("quit")) {
                    throw new QuitException();
                }
                if (userInput.matches("[A-Za-z]+")) {
                    players.add(new Player(userInput));
                    inputValid = true;
                } else {
                    System.out.println("Error: 输入只能包含a-z的英文字母!");
                }
            }
        }
        return players;
    }

    private void printLogo() {
        System.out.println("=== 游戏Logo ===");
    }

    private static void printLogoStatic() {
        System.out.println("=== 游戏Logo ===");
    }

    // Player内部类示例
    public static class Player {
        private final String name;
        public Player(String name) {
            this.name = name;
        }
    }
}

步骤3:在调用层处理异常

在main方法中捕获QuitException,直接返回即可终止程序:

public class Main {
    public static void main(String[] args) {
        try {
            Game game = Game.createGame();
            System.out.println("游戏初始化成功!");
            // 后续游戏逻辑
        } catch (QuitException e) {
            System.out.println("用户终止游戏。");
            // 无需调用System.exit,方法结束后程序自然终止
            return;
        }
    }
}

方案优势

  • 合规性:构造函数仅接收已验证参数,所有final变量都能被正确初始化,符合Java语法规范
  • 简洁性:无需在每一步输入后检查标志位,遇到quit直接抛异常,流程清晰无冗余代码
  • 职责分离:构造函数专注于对象状态初始化,输入验证逻辑由静态工厂方法处理,符合单一职责原则
  • 优雅终止:调用层捕获异常后直接返回,程序自然结束,完全规避System.exit()的使用

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 19:35:46