【问题标题】:java: weird NullPointerException in ternary operator (? : )java:三元运算符中的奇怪 NullPointerException (? : )
【发布时间】:2011-03-09 13:55:29
【问题描述】:

请考虑这个代码sn-p:

private static void doSomething(Double avg, Double min, Double sd) {
    final Double testMin;
    if (avg != null) {
        testMin = Math.max(min, avg - 3 * sd);
    } else {
        testMin = min;
    }
    System.out.println("testMin=" + testMin);

    final Double verwachtMin = avg != null ? Math.max(min, avg - 3 * sd) : min;
    System.out.println("verwachtMin=" + verwachtMin);
}

据我所知(以及我的 IDE 可以告诉我的),变量 testMinverwachtMin 应该是等价的。

如您所料,我宁愿写最后 2 行而不是前 7 行。但是,当我将 3 个空值传递给此方法时,我在计算 verwachtMin 变量时得到 NPE。

有人知道这是怎么回事吗?三元运算符是否评估第二部分,即使条件不是true

(Java 版本 1.6.0_21)

【问题讨论】:

标签: java nullpointerexception ternary-operator


【解决方案1】:

试试:

final Double verwachtMin = avg != null ? new Double(Math.max(min, avg - 3 * sd)) : min;

final Double verwachtMin = avg != null ? Double.valueOf(Math.max(min, avg - 3 * sd)) : min;

三元运算符的交替边的类型是doubleDouble,这意味着Double 被拆箱为double,然后在赋值时我们有一个从double 到@ 的装箱987654328@。如果min 的值为null 则为拆箱NPE。

【讨论】:

  • 谢谢,早该知道的。
  • 这实际上不是一个错误吗?据我所知,Java 将双精度值提升为双精度值是合乎逻辑的,因为另一个值已经是双精度值。我想由于规范/遗留代码,它必须表现得像这样,但这没有多大意义......
  • @MarkusBarthlen 您不希望将值不必要地装箱,因为存在内存管理开销。也许可能存在某种目标类型规则,但重载、目标类型和类型系统的其余部分的混合即使就目前而言也有些过于复杂了。
  • 如果另一个值是 Double,您必须考虑到它可能为 null。即使您会以这种方式节省内存。
【解决方案2】:

三元运算符是否评估第二部分,即使条件 不是真的

否 - 但它评估第三部分,我认为在这种情况下它会尝试自动拆箱 min(导致 NPE),因为 Math.max() 的返回类型是原始 double 并确定返回类型整个表达式。

自动装箱/拆箱是魔鬼。

【讨论】:

  • “整个表达式的返回类型”不是导致拆箱的原因 - 这是 Math.max() 采用 doubles,而不是 Doubles。
  • @Matt:我不认为 Math.max() 的参数在防护表达式为 false 时会被计算
【解决方案3】:

问题是由autoboxing* 引起的,而不是由三元运算符引起的。您正在使用 Double 包装类型而不是 double 原始类型。因为Math.max() 需要double 参数,而不是Doubles,所以在将值传递给Math.max() 之前,有一个对Double#doubleValue() 的不可见调用。但是,您不能在 null 对象上调用方法 - 因此是 NullPointerException

您为什么首先使用Double 而不是double?原始类型变量(例如double)根本不能是null


*好吧,在这种情况下是自动拆箱

【讨论】:

  • 我使用Double而不是double,因为我知道它可能是null
【解决方案4】:

自动拆箱会导致问题。之前已经问过类似的问题..你应该使用双而不是双来解决你的问题..

【讨论】:

    【解决方案5】:

    Math.max(min, avg - 3 * sd) 这里 minavgsd 从 Double 自动拆箱到 double,当其中一个为 null 时会导致 NPE。

    【讨论】:

      猜你喜欢
      • 2016-07-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-29
      • 2023-03-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多