Java基本类型数值溢出不抛异常,而是静默翻转,如int最大值2147483647加1变为-2147483648;需通过Math.addExact()校验、升级long/BigInteger、边界检查及使用包装类常量等方式主动防控。

Java 基本类型数值溢出不会抛异常,而是静默翻转——比如 int 加到 2147483647 后再加 1,结果变成 -2147483648。这种行为极易引发线上故障(如金额错、ID重复、时间倒退),但排查时往往无日志、无堆栈,得靠主动识别和验证。
看字面量和运算是否越界
- 写字面量时注意默认类型:
123是int,123L才是long;1.23默认是double,1.23f才是float - 混合运算要警惕隐式提升:
byte a = 100; byte b = 100; byte c = (byte)(a + b);——不强转会编译报错,因为a + b自动提升为int - 用包装类常量辅助判断:
System.out.println(Integer.MAX_VALUE); // 2147483647 System.out.println(Long.MAX_VALUE); // 9223372036854775807
在关键计算前加断言或日志,比如处理订单金额累加前检查是否接近
Long.MAX_VALUE
查运行时是否已发生溢出
- 对整数运算,用
Math.addExact()、Math.multiplyExact()等方法替代普通+和*:它们会在溢出时直接抛ArithmeticException,便于定位try { long result = Math.addExact(a, b); // 溢出则立即中断 } catch (ArithmeticException e) { log.error("long 加法溢出,a={}, b={}", a, b); } - 对
int/long类型的计数器、ID生成、时间戳差值等高频场景,在测试阶段用-XX:+CheckJNIBounds或 JUnit 配合边界值用例(如MAX_VALUE - 1,MAX_VALUE,MAX_VALUE + 1)覆盖 - 注意
Arrays.sort()、Collections.max()等工具方法内部也可能触发溢出(例如自定义比较器里用a - b计算差值),应改用Integer.compare(a, b)
包装类自动装箱/拆箱带来的隐性溢出风险
Integer.valueOf(int)在-128 ~ 127范围内返回缓存对象,超出范围每次新建对象;但==比较时容易误判相等性,间接掩盖逻辑错误
Java注释规范Skills下载当用户要求为 Java 代码添加注释、修改注释、审查注释、整理注释格式,或要求按照代码注释规范处理 Java 文件时,使用本技能。本技能用于统一生成和维护 Java 类注释模板、按 Git 对比 release 判断版本号、补充每行代码上方中文块注释、调整注释空行规则,并保持 Java 文件 UTF-8 无 BOM 编码。典型触发场景包括:补充类注释、更新 @version、检查 @author 来源、整理行尾注释、把注释放到代码上一行、检查注释是否符合规范、构建前检查 Java 注释风格。
-
最危险的是空指针 + 自动拆箱:
Integer x = null; int y = x; // 运行时报 NullPointerException,不是溢出,但常被误认为“计算出问题”
所以对可能为
null的包装类变量,必须先判空再拆箱,或统一用Objects.requireNonNull(x).intValue() Double和Float不做缓存,但它们的溢出表现不同:1.0 / 0.0得Infinity,-1.0 / 0.0得-Infinity,0.0 / 0.0得NaN;这些值参与后续计算会传染(如NaN == NaN为false),可用Double.isFinite()、Double.isNaN()主动检测
不复杂但容易忽略
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










