java整型溢出静默回绕易引发负数bug,需在long转int、math.abs(integer.min_value)、int乘法赋long、边界除法等高危场景主动防护,优先使用math.*exact()或负数域运算规避。

Java 中整型溢出不会抛异常,而是静默回绕——比如 Integer.MAX_VALUE + 1 得到 Integer.MIN_VALUE,Integer.MIN_VALUE - 1 变成 Integer.MAX_VALUE。这种行为在算术运算中极易引发负数 Bug(如本该是正 ID 却变成负数、时间戳突变、除法逻辑崩溃),关键不是“阻止溢出”,而是提前识别风险点,并用可控方式应对。
Java开发手册规约集合,基于阿里巴巴Java开发手册(嵩山版)。 涵盖7大维度:编程规约、异常日志、单元测试、安全规约、MySQL数据库、工程结构、设计规约。 当用户需要:(1) 编写或审查Java代码 (2) 检查命名/代码规范 (3) 处理异常和日志 (4) 编写单元测试 (5) 安全编码 (6) 数据库设...
明确高危场景,优先加防护
这些地方最容易因溢出产生负数 Bug,必须主动检查: - long → int 强转:`(int)bigId` 或 `(int)System.currentTimeMillis()`,若原值超出 `[-2147483648, 2147483647]`,结果直接错乱(如数据库 BIGINT 主键转成负 ID,查不到记录) - 涉及 Integer.MIN_VALUE 的 Math.abs():`Math.abs(Integer.MIN_VALUE)` 返回的仍是 `-2147483648`,不是 `2147483648`(它根本存不下),后续转 long 也救不回来 - int 乘法/累加后赋给 long:`long x = a * b;` 先按 int 算再截断,中间已溢出,long 接收的是错误值 - 手动实现除法时未处理边界:`dividend == Integer.MIN_VALUE && divisor == -1` 会得到 `2147483648`,超 int 范围用 Math.*Exact() 替代裸运算
Java 8+ 提供带溢出检查的工具方法,失败即抛 `ArithmeticException`,比静默错误更易定位: - `Math.addExact(a, b)`、`Math.multiplyExact(a, b)`、`Math.subtractExact(a, b)` - `Math.toIntExact(longValue)`:替代 `(int)longValue`,超范围立刻报错,避免负数陷阱 - 示例:`int id = Math.toIntExact(resultSet.getLong("id"));` —— 数据库主键安全转 int统一转负数域,避开正数上限
利用负数域更宽(`-2147483648` 存在,`2147483648` 不存在)的特性,把计算移到负数区间: - 手动除法中,不调 `Math.abs(dividend)`,而是先判断符号,再将被除数、除数都转为负数运算 - 示例逻辑:若 `dividend > 0`,则 `dividend = -dividend`;若 `divisor > 0`,则 `divisor = -divisor`;全程用负数比较和减法模拟除法 - 这样 `Integer.MIN_VALUE` 可安全参与,无需担心 `abs` 溢出升阶类型 + 显式转换习惯
别依赖“应该不大”,默认按可能溢出设计: - 累加、计数、幂次、乘积类变量,声明就用 `long`,如 `long sum = 0L;` - 两个 int 相乘前至少转一个为 long:`long result = (long)a * b;`(不是 `a * b` 后再转) - JSON/Protobuf 解析出来的数字默认是 long,别直接 `(int)` 强转——先 `Math.toIntExact()` 或校验范围不复杂但容易忽略
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










