Weird behaviour when using Java ternary operator

我们两清 提交于 2019-12-04 00:27:48

They are not equivalent.

The type of this expression

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

is long because the true result has type long.

The reason this expression is of type long is from section §15.25 of the JLS:

If one of the second and third operands is of primitive type T, and the type of the other is the result of applying boxing conversion (§5.1.7) to T, then the type of the conditional expression is T.

When you lookup a non-existant key the map returns null. So, Java is attempting to unbox it to a long. But it's null. So it can't and you get a NullPointerException. You can fix this by saying:

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

and then you'll be okay.

However, here,

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

since number is declared as Long, that unboxing to a long never occurs.

What is happening here? Both these code paths are exactly equivalent isn't it?

They are not equivalent; the ternary operator has a few caveats.

The if-true argument of the ternary operator, (long) 0, is of the primitive type long. Consequently, the if-false argument will be automatically unboxed from Long to long (as per JLS §15.25):

If one of the second and third operands is of primitive type T, and the type of the other is the result of applying boxing conversion (§5.1.7) to T, then the type of the conditional expression is T.

However, this argument is null (since your map does not contain the string "non-existent key", meaning get() returns null), so a NullPointerException occurs during the unboxing process.

I commented above suggesting that he ensure map never be null, but that does not help with the ternary problem. As a practical matter, it's easier to let the system do the work for you. He could use Apache Commons Collections 4 and its DefaultedMap class.

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

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

Google Guava doesn't have anything as easy as that, but one can wrap map with the Maps.transformValues() method.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!