long比较禁用==,因它比较对象引用而非数值;应使用objects.equals()、longvalue()拆箱或equals()方法,尤其注意orm返回值、stream过滤及单元测试中的高危场景。

Long类型数值比较时直接用==,看似简洁,实则暗藏陷阱——它比的不是值,而是对象引用。一旦涉及自动装箱、缓存机制或跨方法传参,结果可能出人意料。
为什么==在Long比较中不可靠
Java中Long是包装类,==默认比较的是两个对象在堆中的内存地址,而非它们封装的数值。虽然JVM对-128到127之间的Long值做了缓存(通过Long.valueOf()),但超出该范围就会创建新对象:
-
Long a = 100L; Long b = 100L;→a == b为true(命中缓存) -
Long c = 200L; Long d = 200L;→c == d很可能为false(各自新建对象) -
Long e = Long.valueOf(200); Long f = new Long(200);→e == f一定为false(一个是缓存/池中对象,一个是新实例)
安全可靠的替代方案
统一使用语义明确、行为稳定的方法:
- 推荐:
Objects.equals(long1, long2)—— 自动处理null,且对基本类型和包装类都适用 - 简洁场景:
long1.longValue() == long2.longValue()—— 强制拆箱后比较数值,前提是确认不为null - 需判空时:
long1 != null && long2 != null && long1.equals(long2)—— 利用Long.equals()内部已实现的数值比较逻辑
特别注意的高危场景
这些地方最容易误用==并引发线上问题:
- MyBatis等ORM框架返回的主键字段(常为
Long类型),在if判断中直接==比对 - Stream流中用
filter(x -> x.getId() == targetId),targetId来自接口参数(可能为new Long()) - 单元测试里用
assertEquals(expectedId, actual.getId()),但断言库底层用了==(应确保用支持包装类的断言,如AssertJ的isEqualTo())
养成防御性编码习惯
把“看到包装类就警惕==”变成条件反射:
- IDE设置警告:启用
Boxed value is compared using == instead of .equals()类检查(IntelliJ/SpotBugs均支持) - Code Review清单加入:“所有
Long/Integer等包装类比较是否用了.equals()或安全拆箱” - 团队共享模板:将
Objects.equals(a, b)设为默认写法,既防null又保语义
不复杂但容易忽略,一次疏忽可能让相等判断在某些数据上静默失败。把比较逻辑从“看是不是同一个对象”回归到“值是否相等”,才是根本解法。










