使用Java三元操作符时的怪异行为。

时间:2021-02-10 22:29:04

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) to T, then the type of the conditional expression is T.

如果第二个和第三个操作数之一是原始类型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) to T, then the type of the conditional expression is T.

如果第二个和第三个操作数之一是原始类型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) to T, then the type of the conditional expression is T.

如果第二个和第三个操作数之一是原始类型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) to T, then the type of the conditional expression is T.

如果第二个和第三个操作数之一是原始类型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。