
本文解析 java 中因在嵌套循环中错误修改外层循环变量(如 `i`)而引发的无限循环问题,并提供安全、高效的替代方案。
你的代码看似逻辑清晰:目标是计算所有 n 位数的乘积(即每个 n 位数各位数字相乘)之和。但程序卡死,根本原因在于——你在 while 循环中直接修改了外层 for 循环的控制变量 i。
来看关键片段:
for (double i = start; i < finish; i++) {
while (i > 0) {
Digit = i % 10;
MultipliedDigit *= Digit;
i = i / 10; // ⚠️ 危险!这会破坏 for 循环的步进逻辑
}
Summary += MultipliedDigit;
}这里 i 是 double 类型,且在 while 中不断执行 i = i / 10(例如 i=999 → 99.9 → 9.99 → 0.999…),它永远不会真正变为 ≤ 0(浮点精度下可能趋近于 0 但不等于 0),同时 for 循环的 i++ 也因 i 被覆盖而失效——最终导致外层循环永远无法终止。
✅ 正确做法:使用独立的临时变量处理数字拆分,绝不改动循环变量。同时,应改用整数类型(long 或 int)避免浮点误差与性能损耗。
以下是修正后的完整代码:
import java.util.Scanner;
public class SummarynDigitNumbersDigitMultiplyDigit {
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
int n = s.nextInt();
// 边界校验:n 至少为 1
if (n < 1) {
System.out.println(0);
return;
}
long start = (long) Math.pow(10, n - 1); // 最小 n 位数,如 n=2 → 10
long finish = (long) Math.pow(10, n); // 最小 (n+1) 位数,如 n=2 → 100
long summary = 0;
for (long num = start; num < finish; num++) {
long temp = num; // ✅ 用 temp 代替 num 进行各位提取
long multipliedDigit = 1;
// 特殊处理:若 num 含 0,则整个乘积为 0,可提前退出
boolean hasZero = false;
while (temp > 0) {
int digit = (int) (temp % 10);
if (digit == 0) {
hasZero = true;
break;
}
multipliedDigit *= digit;
temp /= 10;
}
if (!hasZero) {
summary += multipliedDigit;
}
// 若含 0,multipliedDigit 不参与累加(保持为 0,无需显式操作)
}
System.out.println(summary);
}
}? 关键改进说明:
- 使用 long num 作为循环变量,long temp 作为副本处理各位数字;
- 所有算术运算基于整数,规避 double 的精度丢失与除法截断问题(如 999/10=99.9 在 double 中不精确,而 999L/10=99L 精确);
- 增加 hasZero 判断:一旦某位为 0,乘积即为 0,可跳过后续计算,提升效率;
- 补充输入校验,防止 n ≤ 0 导致边界异常。
? 小结:在多层循环中,永远不要在内层修改外层循环变量;如需数值变换,请始终使用局部临时变量。这是避免隐蔽无限循环的黄金准则。










