Double.isNaN() 是唯一可靠的 NaN 判等方式;因 IEEE 754 规定 NaN 不等于任何值(含自身),故 == 和 equals() 均返回 false,Objects.equals() 同样失效,安全写法是先判空再调 Double.isNaN(d)。

Double.isNaN() 是唯一靠谱的 NaN 判等方式
直接说结论:用 == 或 .equals() 比较两个 Double 类型的 NaN 值,永远返回 false;必须用 Double.isNaN() 单独判断每个值是否为 NaN,再组合逻辑。
这是因为 IEEE 754 标准明确规定:NaN 不等于任何值,包括它自己。JVM 完全遵循这一规则,所以 Double.NaN == Double.NaN 是 false,new Double(Double.NaN).equals(new Double(Double.NaN)) 也是 false(equals 内部仍用 == 比 double 值)。
-
Double.isNaN(double)接收原始double,性能好,推荐优先用 -
Double.isNaN(Double)是静态重载方法,但会触发自动拆箱,若传入null直接抛NullPointerException - 对
Double对象,安全写法是先判空再调用:d != null && Double.isNaN(d)
用 Objects.equals() 会踩坑
有人想“统一用 Objects.equals(a, b) 处理所有对象”,但对 NaN 这招完全失效——它底层仍是先判引用、再调 a.equals(b),而 Double.equals() 的实现就是 value == other.value,绕不开 NaN 自比为假的问题。
示例:
立即学习“Java免费学习笔记(深入)”;
Double a = Double.NaN; Double b = Double.NaN; System.out.println(a.equals(b)); // false System.out.println(Objects.equals(a, b)); // false System.out.println(Double.isNaN(a) && Double.isNaN(b)); // true
- 别依赖任何基于
equals或==的通用判等工具处理 NaN - 尤其在 DTO 比较、缓存 key 计算、单元测试断言里,容易漏掉 NaN 特殊路径
- 如果业务上“两个 NaN 应视为相等”,必须显式写出
Double.isNaN(x) && Double.isNaN(y)分支
float 和 double 的 NaN 判定不能混用
Float.isNaN(float) 和 Double.isNaN(double) 各自独立,且不能互相替代。把 float 强转成 double 再传给 Double.isNaN() 虽然能运行,但可能掩盖精度问题;更危险的是把 double 值误传给 Float.isNaN()(会先截断为 float,再判断)。
- 保持类型一致:
float值只用Float.isNaN(),double值只用Double.isNaN() - 注意包装类方法签名:
Float.isNaN(Float)和Double.isNaN(Double)都存在,但同样有拆箱空指针风险 - 从 JSON 或数据库读出来的浮点数,需确认实际类型是
float还是double,别凭变量名猜测
单元测试里 NaN 断言最容易漏
写 JUnit 测试时,如果被测方法可能返回 NaN(比如除零、无效数学运算),用 assertEquals(expected, actual) 会静默失败——因为 expected 是 NaN 时,断言直接报 “expected: NaN but was: NaN”,看起来一样,实则底层比较结果为 false。
- JUnit 5 推荐用
assertTrue(Double.isNaN(actual))显式断言 NaN - 若要对比两个可能含 NaN 的结果,得拆成逻辑判断:
assertTrue(Double.isNaN(a) == Double.isNaN(b) ? (Double.isNaN(a) || a == b) : false) - Mockito 的
when().thenReturn(Double.NaN)没问题,但 verify 时别用eq(Double.NaN),它底层还是==


















