关键在于理解装箱拆箱的隐式行为并主动规避副作用:避免null包装类直接拆箱引发npe;用equals()而非==比较值;性能敏感路径禁用自动装箱拆箱。

关键不在“怎么设计”,而在于理解装箱拆箱的隐式行为,并主动规避它的副作用。自动装箱和拆箱是编译器提供的语法糖,本身不可更改,但你可以通过规范用法来大幅提升代码健壮性。
避免在可能为 null 的包装类上直接拆箱
这是引发 NPE 的最高频场景。只要包装类变量未做空校验就参与算术、比较或赋值,运行时就会崩溃。
- 错误写法:int value = optionalInt;(当 optionalInt == null 时抛 NPE)
- 安全写法:先判空,或使用三元表达式提供默认值,例如 int value = optionalInt != null ? optionalInt : 0;
- 更优实践:用 Optional
替代 Integer 作返回值或入参,强制调用方处理空值
慎用 == 比较包装类对象
== 比较的是引用,不是值。Integer 在 -128 到 127 范围内会复用缓存对象,超出范围则每次新建实例,导致相同数值比较结果不一致。
- 危险示例:Integer a = 128; Integer b = 128; System.out.println(a == b); // false
- 统一做法:所有包装类值比较一律用 equals(),它内部已对 null 做了防护(如 Integer.equals() 会先判空再比值)
- 特殊情况:若确定两个变量非 null,且需高性能比较(如高频循环),可用 Objects.equals(a, b),语义清晰又防 NPE
性能敏感路径禁用自动装箱/拆箱
循环中对 Long、Integer 等做累加或频繁集合操作,会反复创建/销毁对象,拖慢执行速度并增加 GC 压力。
- 反模式:Long sum = 0L; for (int i = 0; i (每次 += 都触发拆箱+装箱)
- 推荐方案:用基本类型替代,如 long sum = 0;;集合操作若必须用泛型,考虑用 IntStream 或第三方库(如 Eclipse Collections)提供的原始类型集合
- 注意边界:日志、调试、配置读取等低频场景无需过度优化,可优先保障可读性
明确区分基本类型与包装类的语义用途
基本类型表示“一定有值”的数值;包装类应承载“可选值”或“需要对象特性”的语义(如泛型、反射、序列化)。
- 参数设计:方法入参若允许缺失,用 Integer;若业务上必填,坚持用 int,让编译器和调用方都明确契约
- DTO/VO 字段:数据库字段允许 NULL 时,用包装类;主键、状态码等非空字段,用基本类型 + 显式默认值(如 status: int = 0)
- 避免无意义包装:不要把 int x = 5; 写成 Integer x = 5; 再到处拆箱,徒增风险
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











