When I write my java code like this:
Map map = new HashMap<>()
Long number =null;
if(map == null)
number = (long) 0;
else
numbe
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) toT
, then the type of the conditional expression isT
.
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.
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) toT
, then the type of the conditional expression isT
.
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.
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.