
Java中哪些操作会直接抛出ArithmeticException
只有整数类型的除法(/)和取模(%)在除数为零时,JVM 会强制抛出 ArithmeticException;浮点数运算不会——它返回 Infinity 或 NaN,不报异常。
-
int a = 5 / 0;→ 立即抛ArithmeticException: / by zero -
long b = 10 % 0;→ 同样抛ArithmeticException: / by zero -
double c = 5.0 / 0.0;→ 结果是Infinity,无异常 -
float d = 0.0f / 0.0f;→ 结果是NaN,无异常
为什么ArithmeticException是运行时异常,且不能靠编译器提前发现
因为除数是否为零,往往取决于运行时变量值,编译器无法静态判定。即使写成 int x = 0; int y = 5 / x;,JVM 仍要等到执行到该字节码指令时才检查。
- 编译阶段只校验语法和类型,不计算表达式结果
- 常量折叠(如
5 / 0)在部分 JDK 版本中会被编译器拦截并报错,但这是特例,不是规范保证 - 一旦涉及变量、方法返回值、用户输入等,就完全逃逸编译检查
常见踩坑:误以为try-catch能覆盖所有“数学错误”
ArithmeticException 只管整数除零和模零;其他数值问题比如溢出(Integer.MAX_VALUE + 1)、下溢、精度丢失,都不会触发它。
-
int overflow = Integer.MAX_VALUE + 1;→ 结果是Integer.MIN_VALUE,静默回绕,无异常 -
new BigDecimal("1").divide(new BigDecimal("3"), 2, RoundingMode.HALF_UP)→ 若未指定精度可能抛ArithmeticException,但这是BigDecimal自己的逻辑,和 JVM 整数运算是两回事 - 用
Math.multiplyExact()或Math.addExact()才会主动检测溢出并抛ArithmeticException,但这属于显式调用,不是自动行为
实际防御建议:什么时候该检查,什么时候可放心忽略
对整数除法/取模,只要除数来源不可控(参数、配置、数据库字段、用户输入),就必须手动判零;若确定是编译期常量或已验证过的内部逻辑(如循环索引非零),可不加检查。
立即学习“Java免费学习笔记(深入)”;
- 接口入参做除法前:先
if (divisor == 0) throw new IllegalArgumentException("divisor must not be zero"); - 避免在
catch (ArithmeticException e)里吞掉异常再返回默认值——掩盖了本该被发现的逻辑缺陷 - 注意
OptionalInt或返回Double等替代方案,有时比硬扛异常更清晰,尤其当“除零”在业务上代表“无定义”而非错误时










