Java自动装箱和三元运算符疯狂

Java自动装箱和三元运算符疯狂,java,operator-keyword,autoboxing,ternary,Java,Operator Keyword,Autoboxing,Ternary,刚刚花了几个小时调试这段代码: LinkedHashMap<String, Integer> rsrqs = new LinkedHashMap<String, Integer>(); Integer boxedPci = 52; Integer boxedRsrq = boxedPci != null ? rsrqs.get(boxedPci.toString()) : -1; LinkedHashMap rsrqs=new LinkedHas

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

    LinkedHashMap<String, Integer> rsrqs = new LinkedHashMap<String, Integer>();
    Integer boxedPci = 52;
    Integer boxedRsrq = boxedPci != null ? rsrqs.get(boxedPci.toString()) : -1;
LinkedHashMap rsrqs=new LinkedHashMap();
整数dpci=52;
整数boxedRsrq=boxedPci!=无效的get(boxedPci.toString()):-1;
上面生成一个NullPointerException。以下代码不适用:

    LinkedHashMap<String, Integer> rsrqs = new LinkedHashMap<String, Integer>();
    Integer boxedPci = 52;
    Integer boxedRsrq = boxedPci != null ? rsrqs.get(boxedPci.toString()) : Integer.valueOf(-1);
LinkedHashMap rsrqs=new LinkedHashMap();
整数dpci=52;
整数boxedRsrq=boxedPci!=无效的get(boxedPci.toString()):Integer.valueOf(-1);
唯一的区别是用Integer.valueOf()包装-1。我敢肯定,一旦有人解释了为什么这段代码会以这种方式运行,我会大发雷霆。。但是有人能给我解释一下为什么这段代码是这样的:)

-- 编辑


再想一想,我怀疑NPE来自返回null的rsrqs.get(),我认为java试图在返回整数之前将其解装箱为int。valueOf()强制Java执行取消装箱步骤。故事的寓意;不要忽略Eclipse中的装箱警告;)

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

然后对表达式
rsrqs.get(boxedPci.toString())
求值,并将其强制为类型
int
,以匹配三元表达式,但因为它是
null
,所以会抛出NPE

通过装箱
-1
,三元表达式的值是
整数
,因此您是空安全的

1
是整数,不是整数。因此,Java将把整数反装箱为int,这将导致NullPointerException。自动取消对空整数的装箱时,会导致NullPointerException。()

但是当你使用

 Integer.valueOf(-1) 

它不需要自动取消装箱,这不会导致任何异常。

可以从中的信息得出解释

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

然而,这意味着

Integer boxedRsrq = boxedPci != null ? rsrqs.get(boxedPci.toString()) : -1;
在语义上与

Integer boxedRsrq = boxedPci != null ? ((int)rsrqs.get(boxedPci.toString())) : -1;
但这意味着如果从映射中获得
null
,就会得到
NullPointerException
,这显然会发生

如果将第三个操作数强制转换为
整数
,则第二个操作数将永远不会强制转换为
int
,并且不会发生NPE。

那么,返回一个
整数
,并且-1是一个基元
int
。第一个示例被迫取消装箱,因为一个术语是原语。你也可以用

Integer boxedRsrq = boxedPci != null ? 
    rsrqs.get(boxedPci.toString()) : (Integer) -1;

它会将-1装箱。

没有人给我NPE,请检查code@Chechus测试之后,使用Java1.8,结果会有所不同(返回null,无NPE)。想法?@Chechus:Java8的类型推断要好得多。这是lambda表达式支持的一个副作用。我的猜测是,三元表达式的类型现在正受到接收器类型的影响(即,它被分配给一个
整数
,因此让我们将表达式的类型设置为
整数
,并停止尝试取消空值的装箱)@skaffman:这似乎是实现更好的类型推断的一个副作用,但是通过阅读规范,我感觉到,您不应该依赖它,因为“数值条件表达式”被显式地声明为没有“多边形表达式”,read,不受目标类型的影响;而且规格可能也不好。请参见中的最后一个示例