java 8起math类提供addexact等exact方法,专用于int/long运算溢出时抛arithmeticexception,避免静默回绕;需逐次调用、显式处理异常,不检查null、不保证线程安全。

Java 8 起,Math 类提供了一组 Exact 方法(如 addExact、multiplyExact、subtractExact、negateExact、toIntExact),专为在整型运算**结果溢出时主动抛出 ArithmeticException** 而设计。它们不是事后检查,而是在计算执行的同一时刻完成溢出判定,避免静默回绕(比如 Integer.MAX_VALUE + 1 变成 Integer.MIN_VALUE)。
只对 int 和 long 生效,类型必须匹配
这些方法仅支持 int 和 long 两种基本类型,各有对应重载:
-
Math.addExact(int, int)、Math.addExact(long, long) -
Math.multiplyExact(int, int)、Math.multiplyExact(long, long) - 其他如
subtractExact、negateExact、toIntExact同理
传入 short、byte、char 会自动提升为 int,调用的是 int 版本;想用 long 版本,至少一个操作数需带 L 后缀(如 Math.multiplyExact(10L, x))。包装类(如 Integer)会自动拆箱,但要注意 null 会导致 NullPointerException,不是溢出异常。
不能把普通运算塞进参数里
常见错误是写成 Math.addExact(a + b, c)——此时 a + b 已静默溢出,addExact 校验的是一个错误中间值,完全失效。
正确做法是链式调用或逐次校验:
- 两个数:
int sum = Math.addExact(a, b); - 三个数:
int sum = Math.addExact(Math.addExact(a, b), c); - 多个数累加(如计数器):
sum = Math.addExact(sum, nextValue);放在循环中逐次执行
异常必须显式应对,不能忽略
ArithmeticException 是运行时异常,编译器不强制捕获,但 IDE 通常会提示。业务上它代表“约束被突破”,不是程序 bug,因此建议:
- 关键路径(如支付金额、索引计算)中,用
try-catch捕获后包装为更明确的业务异常,例如:throw new IllegalStateException("订单总金额超出系统支持范围", e); - 批量处理场景可记录日志、告警、跳过当前项,避免整批失败
- 避免在
catch中吞掉异常或返回默认值(如0或-1),否则又回到静默错误的老路
它快且专注,但有明确边界
底层由 JVM 高度优化(HotSpot 常内联为带溢出标志检测的汇编指令),性能几乎与原生运算一致,远优于手写边界判断。
但它只做一件事:确保**该次运算结果在目标类型范围内**。它不负责:
- 检查参数是否为
null(基本类型无此问题,但包装类需自行判空) - 保证线程安全(多线程更新同一变量仍需
AtomicInteger或锁) - 覆盖隐性溢出点(如
for (int i = start; i 中 <code>i回绕、时间戳差值误存为int)











