Java基本类型运算不抛异常,但包装类隐式拆箱易致NPE和静默溢出;需判空防NPE、用Math.exact系列或手动边界检查防溢出、优先选基本类型、比较用Objects.equals。

Java 基本类型本身不会在算术运算中抛异常,真正出问题的是包装类(如 Integer、Long)参与运算时的隐式拆箱和静默溢出。关键不是“防止运算报错”,而是避免 空指针(NPE) 和 静默数据错误 这两类风险。
拆箱前必须判空,否则必抛 NPE
只要包装类变量为 null,任何触发自动拆箱的操作都会立即抛 NullPointerException:
-
Integer a = null; int b = a + 1;→ 拆箱失败 -
Boolean flag = null; if (flag) { ... }→ 拆箱失败 -
Integer x = null, y = 5; Integer z = x + y;→ 同样失败(先拆 x)
安全做法是显式控制拆箱时机:
- 用
Objects.requireNonNullElse(a, 0)获取默认值 - 三元表达式中提前检查:
int v = (a != null) ? a : -1; - 方法入参若为包装类,入口处用
Objects.requireNonNull(a, "a required")明确拦截
避免静默溢出:别依赖 int 加减乘后还“看起来对”
基本类型运算不报错,但会绕回(如 Integer.MAX_VALUE + 1 == Integer.MIN_VALUE)。这在计数、分页、金额等场景极易引发严重逻辑错误。
立即学习“Java免费学习笔记(深入)”;
- 优先使用
Math.addExact(a, b)、Math.multiplyExact(a, b)等方法——溢出直接抛ArithmeticException,把隐患暴露出来 - 高频或底层代码中无法抛异常?改用手动边界判断,例如加法:
a > 0 && b > 0 && a > Integer.MAX_VALUE - b - 别写
(long)(a * b)——错误!a * b已在 int 层溢出;应写(long) a * b或a * 1L * b
该用基本类型就别用包装类
如果变量不会为 null,也不需要表达“缺失”语义(比如数据库字段非空、方法参数必填),就直接用 int、long、boolean 等基本类型:
- 集合中确实要放数字?用
int[]、LongArrayList(如 Trove 或 Eclipse Collections),而非ArrayList<integer></integer> - 数据库映射或 JSON 解析时,配置框架默认填充基础类型(如 MyBatis-Plus 的
@TableField(fill = FieldFill.INSERT),Jackson 的@JsonSetter(nulls = Nulls.SKIP)) - 返回值若无“空值”含义,就别返回
Integer,直接返回int或封装成Optional<integer></integer>
数值比较别踩 == 陷阱
用 == 比较两个 Integer 变量,结果不可靠:
Integer a = 127, b = 127; System.out.println(a == b); // true(缓存命中)Integer c = 128, d = 128; System.out.println(c == d); // false(新对象)
统一用 Objects.equals(a, b) ——它自动处理 null,且语义是“值相等”,不是“引用相同”。混合比较(如 int a == Integer b)虽可编译,但前提是 b != null,否则仍 NPE。


















