应优先用 ThreadLocalRandom,多线程下 Random 易因重复种子导致结果不公;单线程需复用 Random 实例;do-while 更适合至少执行一次的重投逻辑;输入处理宜用 while(true) 配 if-else 分支;点数范围等须定义常量以利扩展;输出注意换行与 Scanner 输入清理。

用 Random 还是 ThreadLocalRandom?选错会影响公平性
骰子游戏的核心是“不可预测的整数”,Java 里最常用的是 Random,但它在多线程场景下可能被重复种子初始化(尤其在快速连续创建实例时),导致连续几次掷出相同点数。生产级或高并发模拟中应优先用 ThreadLocalRandom.current().nextInt(1, 7)——它线程安全、无竞争、且默认范围是左闭右开,nextInt(1, 7) 恰好生成 1~6 的整数。
单线程小游戏可直接用 Random,但别写成 new Random().nextInt(6) + 1:每次 new 都可能复用系统时间作为种子,若循环太快,会得到一串重复值。正确做法是复用一个实例:
Random dice = new Random(); int roll = dice.nextInt(6) + 1;
用 while 还是 do-while 控制重投逻辑?
用户输入“r”重掷、“q”退出——这种“至少执行一次”的交互,do-while 更自然。如果用 while,就得先手动调一次掷骰逻辑,代码冗余且易漏。
常见错误是把输入判断和掷骰耦合进同一层循环条件,导致无法响应无效输入(比如输了个“x”):
立即学习“Java免费学习笔记(深入)”;
- ❌ 错误:
while (input.equals("r")) { ... }—— 输“q”就直接退出,没机会提示“输入无效” - ✅ 正确:外层用
while (true),内部用if-else if-else分支处理 “r” / “q” / 其他
这样能清晰分离「读输入」「判指令」「执行动作」三步,也方便后续加新指令(如 “h” 显示帮助)。
如何避免硬编码导致后期难扩展?
骰子点数范围(1–6)、面数(6)、甚至骰子个数(单骰/双骰)都该抽成常量或配置。硬写 nextInt(6) + 1 看似简单,但想改成二十面骰(d20)时,要改所有出现位置,还容易漏掉 +1。
推荐定义:
private static final int DICE_MIN = 1; private static final int DICE_MAX = 6; // 后续只需改这里,其余逻辑自动适配 int roll = random.nextInt(DICE_MAX - DICE_MIN + 1) + DICE_MIN;
如果支持多骰,用数组存结果比拼接字符串更利于统计(比如“是否出现豹子”“总和是否大于10”):
int[] rolls = new int[2]; rolls[0] = random.nextInt(6) + 1; rolls[1] = random.nextInt(6) + 1;
控制台输出容易忽略的细节:清屏与回车
Java 标准库不提供跨平台清屏(cls 或 clear),强行调用 Runtime.getRuntime().exec("clear") 在 Windows 上会失败。更稳妥的做法是输出若干空行模拟“清屏”效果,或干脆不清理——但必须确保每次输出结尾有 \n,否则下一行提示符会黏在数字后面。
另一个坑是用户输完按回车,Scanner.nextLine() 会读到空字符串,如果紧接着又调一次 nextLine(),就会跳过实际输入。统一用 nextLine() 并 trim() 是最稳的:
String input = scanner.nextLine().trim();
if (input.equalsIgnoreCase("r")) { ... }别用 next(),它不吞回车符,残留换行符会让后续 nextLine() 立刻返回空串。










