ArithmeticException是Java中不强制捕获的运行时异常,仅在int、long等整数类型除零时抛出;float/double除零返回Infinity或NaN;应前置校验分母而非依赖try-catch。

ArithmeticException 是什么,为什么只在整数除零时抛出
ArithmeticException 是 Java 中的运行时异常,继承自 RuntimeException,**不强制要求 try-catch**。但它只在整数类型(int、long、short、byte)执行除零操作时触发;浮点数(float、double)除零不会抛异常,而是返回 Infinity 或 NaN。
常见错误现象:
- 写
int result = 10 / 0;→ 直接崩溃,报java.lang.ArithmeticException: / by zero - 误以为
double d = 5.0 / 0.0;也会抛异常 → 实际返回Infinity,后续可能引发逻辑错但不中断
如何安全处理整数除法中的除零风险
核心原则:**不能依赖 catch 来兜底,而应在运算前校验分母**。因为 ArithmeticException 属于程序逻辑缺陷,不是外部不可控异常(如 IO 失败),应预防而非捕获。
实操建议:
立即学习“Java免费学习笔记(深入)”;
- 对所有用户输入或外部传入的除数,先判断是否为
0,例如:if (divisor == 0) { throw new IllegalArgumentException("Divisor cannot be zero"); } - 使用
Math.floorDiv(a, b)或Math.floorMod(a, b)(Java 8+)?注意:它们同样会在b == 0时抛ArithmeticException,不规避问题 - 若业务允许默认值,可用三元表达式:
int result = divisor != 0 ? dividend / divisor : 0; - 避免在循环内反复 try-catch 整数除法 —— 性能差且掩盖设计问题
BigDecimal 除法不抛 ArithmeticException?那它怎么报错
BigDecimal 的除法行为完全不同:divide() 方法在无法整除且未指定舍入模式时,抛的是 ArithmeticException,但原因不是“除零”,而是“除不尽且无舍入规则”。
关键区别:
-
new BigDecimal("10").divide(new BigDecimal("3"))→ 抛ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result -
new BigDecimal("10").divide(new BigDecimal("0"))→ 才是真正的除零,抛同名异常,但消息是Division by zero - 正确用法必须显式指定舍入:
bd1.divide(bd2, 2, RoundingMode.HALF_UP)
日志和调试中快速定位 ArithmeticException 源头
堆栈里只显示 / by zero,但实际除法可能嵌套在方法链或计算表达式中(如 foo(x / y) + bar(z / w)),难以一眼看出哪个变量为零。
建议做法:
- 将除法单独提取为带变量名的语句,便于断点和日志:
int denominator = getConfiguredPort(); if (denominator == 0) log.warn("port is zero!"); int result = 100 / denominator; - 在 IDE 中启用 “Break on Exception” 并勾选
ArithmeticException,它会停在真正执行除零的那一行,而不是上层调用处 - 静态分析工具(如 SpotBugs)能检测部分硬编码除零(如
10 / 0),但对变量参与的除法无能为力 —— 这正是需要人工校验的地方
最易被忽略的一点:布尔表达式里的短路逻辑不会保护除法,比如 flag && (x / y > 0),若 flag 为 true 且 y == 0,仍会触发异常 —— 除法运算优先级高于逻辑与,且不被短路控制。










