Java autoboxing和三元运算符疯狂

Exp*_*ent 19 java autoboxing ternary operator-keyword

只花了几个小时调试这段代码:

    LinkedHashMap<String, Integer> rsrqs = new LinkedHashMap<String, Integer>();
    Integer boxedPci = 52;
    Integer boxedRsrq = boxedPci != null ? rsrqs.get(boxedPci.toString()) : -1;
Run Code Online (Sandbox Code Playgroud)

以上产生了NullPointerException.以下代码不:

    LinkedHashMap<String, Integer> rsrqs = new LinkedHashMap<String, Integer>();
    Integer boxedPci = 52;
    Integer boxedRsrq = boxedPci != null ? rsrqs.get(boxedPci.toString()) : Integer.valueOf(-1);
Run Code Online (Sandbox Code Playgroud)

唯一的区别是用Integer.valueOf()包装-1.一旦有人解释了为什么这个代码的行为方式,我肯定我会打破我的前额..但有人可以向我解释为什么这个代码的行为方式:)

- 编辑

第二个想法,我怀疑NPE来自rsrqs.get()返回null,我认为java在尝试解包成int之前,然后再回到整数.Integer.valueOf()强制Java执行unbox-box步骤.故事的道德启示; 不要只忽略Eclipse中的那些拳击警告;)

ska*_*man 27

与任何表达式一样,三元表达式具有由编译器确定的类型.如果三元表达式的两边看起来像不同的类型,那么编译器将尝试使用两个选项中最不模糊的类型来查找公共基类型.在您的情况下,-1最不明确,因此三元表达式的类型是int.遗憾的是,编译器不使用基于接收变量的类型推断.

rsrqs.get(boxedPci.toString())然后计算表达式并强制进入类型int以匹配三元表达式,但因为null它抛出了NPE.

通过装箱-1,三元表达式的值是Integer,所以你是空的安全.

  • @Chechus:Java8的类型推断要好得多.这是lambda表达式支持的副作用.我的猜测是三元表达式的类型现在受到接收器类型的影响(即它被分配给`Integer`,所以让我们创建表达式`Integer`的类型并停止尝试取消对null的取消) (3认同)

fab*_*ian 11

可以从java语言规范中的信息得出结论:15.25.条件运算符?:.

从那里的表中,您可以获得信息,如果第二个操作数(rsrqs.get(boxedPci.toString()))是类型Integer而第三个操作数是类型int,则结果将是类型int.

然而,这意味着,那

Integer boxedRsrq = boxedPci != null ? rsrqs.get(boxedPci.toString()) : -1;
Run Code Online (Sandbox Code Playgroud)

在语义上是相同的

Integer boxedRsrq = boxedPci != null ? ((int)rsrqs.get(boxedPci.toString())) : -1;
Run Code Online (Sandbox Code Playgroud)

但这意味着NullPointerException,如果你null从地图上得到了,那么你会得到一个明显发生的事情.

如果将第三个操作数转换为Integer,则第二个操作数将永远不会被转换为int并且不会发生NPE.