When I write my java code like this:
当我这样编写java代码时:
Map<String, Long> map = new HashMap<>()
Long number =null;
if(map == null)
number = (long) 0;
else
number = map.get("non-existent key");
the app runs as expected but when I do this:
应用程序按预期运行,但当我这样做时:
Map<String, Long> map = new HashMap<>();
Long number= (map == null) ? (long)0 : map.get("non-existent key");
I get a NullPointerException on the second line. The debug pointer jumps from the second line to this method in the java.lang.Thread class:
在第二行得到NullPointerException。调试指针从第二行跳到java.lang中的这个方法。线程类:
/**
* 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);
}
What is happening here? Both these code paths are exactly equivalent isn't it?
这里正在发生什么?这两个代码路径都是完全等价的,不是吗?
Edit
编辑
I am using Java 1.7 U25
我正在使用Java 1.7 U25
3 个解决方案
#1
15
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:
这个表达式的类型是长时间的原因是来自§15.25段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
.如果第二个和第三个操作数之一是原始类型T,和其他的类型是应用拳击转换的结果(§5.1.7)T,然后条件表达式的类型是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:
当您查找一个不存在的键时,映射返回null。因此,Java正试图将其打开很长一段时间。但这是null。它不能,你会得到一个NullPointerException。你可以这样说:
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.
由于数字被声明为“长”,所以对“长”的取消从来不会发生。
#2
3
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):
三元运算符(long) 0的if-true参数是原始类型long。因此,如果错误参数会自动从箱子中取出从长时间长(按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
.如果第二个和第三个操作数之一是原始类型T,和其他的类型是应用拳击转换的结果(§5.1.7)T,然后条件表达式的类型是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.
但是,这个参数是null(因为您的映射不包含字符串“不存在的键”,这意味着get()返回null),所以在取消装箱过程中会发生NullPointerException。
#3
0
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.
我在上面评论说,他确保map永远不会为空,但这对三元问题没有帮助。作为一个实际问题,让系统为您做这些工作更容易。他可以使用Apache Commons Collections 4及其默认映射类。
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.
谷歌番石榴没有这么简单的东西,但是可以使用map . transformvalues()方法包装map。
#1
15
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:
这个表达式的类型是长时间的原因是来自§15.25段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
.如果第二个和第三个操作数之一是原始类型T,和其他的类型是应用拳击转换的结果(§5.1.7)T,然后条件表达式的类型是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:
当您查找一个不存在的键时,映射返回null。因此,Java正试图将其打开很长一段时间。但这是null。它不能,你会得到一个NullPointerException。你可以这样说:
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.
由于数字被声明为“长”,所以对“长”的取消从来不会发生。
#2
3
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):
三元运算符(long) 0的if-true参数是原始类型long。因此,如果错误参数会自动从箱子中取出从长时间长(按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
.如果第二个和第三个操作数之一是原始类型T,和其他的类型是应用拳击转换的结果(§5.1.7)T,然后条件表达式的类型是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.
但是,这个参数是null(因为您的映射不包含字符串“不存在的键”,这意味着get()返回null),所以在取消装箱过程中会发生NullPointerException。
#3
0
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.
我在上面评论说,他确保map永远不会为空,但这对三元问题没有帮助。作为一个实际问题,让系统为您做这些工作更容易。他可以使用Apache Commons Collections 4及其默认映射类。
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.
谷歌番石榴没有这么简单的东西,但是可以使用map . transformvalues()方法包装map。