繁体   English   中英

使用Java三元运算符时的奇怪行为

[英]Weird behaviour when using Java ternary operator

当我写这样的java代码时:

Map<String, Long> map = new HashMap<>()
Long number =null;
if(map == null)
    number = (long) 0;
else
    number = map.get("non-existent key");

应用程序按预期运行但是当我这样做时:

Map<String, Long> map = new HashMap<>();
Long number= (map == null) ? (long)0 : map.get("non-existent key");

我在第二行得到一个NullPointerException。 调试指针从第二行跳转到java.lang.Thread类中的this方法:

 /**
     * Dispatch an uncaught exception to the handler. This method is
     * intended to be called only by the JVM.
     */
     private void dispatchUncaughtException(Throwable e) {
         getUncaughtExceptionHandler().uncaughtException(this, e);
     }

这里发生了什么? 这两个代码路径都完全等价不是吗?


编辑

我使用的是Java 1.7 U25

他们并不等同。

这个表达式的类型

(map == null) ? (long)0 : map.get("non-existent key");

long因为真正的结果类型long

此表达式的类型为long的原因来自JLS的15.25节:

如果第二和第三个操作数中的一个是原始类型的T ,其它的类型是施加装箱转换(§5.1.7)到的结果T ,那么条件表达式的类型是T

查找不存在的键时, map返回null 因此,Java试图将其拆箱很long 但它是null 所以它不能,你得到一个NullPointerException 您可以通过说:

Long number = (map == null) ? (Long)0L : map.get("non-existent key");

然后你会没事的。

但是,在这里,

if(map == null)
    number = (long) 0;
else
    number = map.get("non-existent key");

因为number被声明为Long ,这拆箱到long永远不会发生。

这里发生了什么? 这两个代码路径都完全等价不是吗?

它们并不等同; 三元运算符有一些警告。

三元运算符的if-true参数(long) 0 ,是原始类型long 因此,if-false参数将从Longlong自动取消装箱(根据JLS§15.25 ):

如果第二和第三个操作数中的一个是原始类型的T ,其它的类型是施加装箱转换(结果§5.1.7 )到T ,那么条件表达式的类型是T

但是,此参数为null (因为您的映射不包含字符串"non-existent key" ,这意味着get()返回null ),因此在取消装箱过程中会发生NullPointerException

我在上面评论过,他建议他确保map永远不会为null ,但这对三元问题没有帮助。 实际上,让系统为您完成工作更容易。 他可以使用Apache Commons Collections 4及其DefaultedMap类。

import static org.apache.commons.collections4.map.DefaultedMap.defaultedMap;

Map<String, Long> map = ...;  // Ensure not null.
Map<String, Long> dMap = defaultedMap(map, 0L); 

谷歌番石榴没有那么简单,但可以使用Maps.transformValues()方法包装map

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM