【问题标题】:Conditional operators in Java throw an unexpected NullPointerException [duplicate]Java中的条件运算符抛出意外的NullPointerException [重复]
【发布时间】:2012-10-17 15:05:57
【问题描述】:

可能重复:
NullPointerException through auto-boxing-behavior of Java ternary operator

以下代码使用简单的条件运算符。

public class Main
{
    public static void main(String[] args)
    {
        Integer exp1 = true ? null : 5;
        Integer exp2 = true ? null : true ? null : 50;

        System.out.println("exp1 = " +exp1+" exp2 = "+exp2);

        Integer exp3 = false ?  5 : true ? null: 50; //Causes the NullPointerException to be thrown.

        System.out.println("exp3 = "+exp3);
    }
}

这段代码编译得很好。所有表达式最终都尝试将null 分配给Integer 类型变量exp1exp2exp3

前两种情况不要抛出任何异常并产生exp1 = null exp2 = null,这是显而易见的。

然而,最后一种情况,如果你仔细看,你会看到它还试图将null 分配给Integer 类型变量exp3,看起来与前两种情况类似,但它会导致@987654333 @被抛出。为什么会这样?

在我发布我的问题之前,我已经提到了this 很好的问题,但在这种情况下,我找不到 JLS 指定的规则适用于此处。

【问题讨论】:

  • ?: 运算符使代码不那么明显。如果您使用了if-then-else,就不会产生混淆。
  • 操作员没有抛出这个异常。 您的操作数之一在评估期间抛出了它。

标签: java nullpointerexception conditional-operator


【解决方案1】:

null 被拆箱到int,因为分配是由于5int,而不是Integer。但是,null 不能表示为int,因此NullPointerException

如果您将5 替换为new Integer(5),那么它将起作用。

Integer exp3 = false ? new Integer(5) : true ? null : 50;

另见:

【讨论】:

  • 只是补充说明:exp3 赋值中的表达式true ? null : 50 正在int 上下文中进行评估。当在对exp2 的赋值中计算相同的表达式时,它位于Integer 上下文中。
【解决方案2】:

它正在拆箱null,因此它与?: 表达式中的其他两个值的类型相同。 exp1exp2 不要触发这个。

public class Foo {
    public static void main(String...args) {
        Integer exp3 = false ?  5 : true ? null: 50; //Causes the NullPointerException to be thrown.
        System.out.println("exp3 = "+exp3);
    }  
}

运行javap -c Foo 后,我们得到这个反汇编:

public static void main(java.lang.String[]);
  Code:
   0:   aconst_null
   1:   checkcast   #2; //class java/lang/Integer
   4:   invokevirtual   #3; //Method java/lang/Integer.intValue:()I
   7:   invokestatic    #4; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
   10:  astore_1
   11:  getstatic   #5; //Field java/lang/System.out:Ljava/io/PrintStream;
   14:  new #6; //class java/lang/StringBuilder
   17:  dup
   ....

注意 4:invokevirtual #3 -- 它正试图在此处拆箱 null

【讨论】:

  • 这特别有趣,因为它揭示了编译器是多么有趣。跳过所有条件句足够聪明,但不够聪明,只需将其替换为 throw new NullPointerException()
  • 我认为人们可能因为您是 tl;dr 而对您投了反对票,但我喜欢您的解决方案,因为您向 OP 展示了如何在未来为自己回答此类问题。 ;)
猜你喜欢
  • 2018-03-21
  • 2011-12-31
  • 2016-05-21
  • 1970-01-01
  • 2015-07-16
  • 2018-06-20
  • 1970-01-01
  • 2016-07-09
  • 1970-01-01
相关资源
最近更新 更多