Java 可以从 null 转换为 int 吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6588856/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Conversion from null to int possible?
提问by Giorgio
I know that when I read the answer to this I will see that I have overlooked something that was under my eyes. But I have spent the last 30 minutes trying to figure it out myself with no result.
我知道当我阅读这个答案时,我会发现我忽略了我眼前的一些东西。但在过去的 30 分钟里,我一直在试图自己弄清楚,但没有结果。
So, I was writing a program in Java 6 and discovered some (for me) strange feature. In order to try and isolate it, I have made two small examples. I first tried the following method:
所以,我在用 Java 6 编写程序时发现了一些(对我来说)奇怪的特性。为了尝试和隔离它,我做了两个小例子。我首先尝试了以下方法:
private static int foo()
{
return null;
}
and the compiler refused it: Type mismatch: cannot convert from null to int.
并且编译器拒绝了它:类型不匹配:无法从 null 转换为 int。
This is fine with me and it respects the Java semantics I am familiar with. Then I tried the following:
这对我来说很好,它尊重我熟悉的 Java 语义。然后我尝试了以下方法:
private static Integer foo(int x)
{
if (x < 0)
{
return null;
}
else
{
return new Integer(x);
}
}
private static int bar(int x)
{
Integer y = foo(x);
return y == null ? null : y.intValue();
}
private static void runTest()
{
for (int index = 2; index > -2; index--)
{
System.out.println("bar(" + index + ") = " + bar(index));
}
}
This compiles with no errors! But, in my opinion, there should be a type conversion error in the line
这编译没有错误!但是,在我看来,该行中应该存在类型转换错误
return y == null ? null : y.intValue();
If I run the program I get the following output:
如果我运行程序,我会得到以下输出:
bar(2) = 2
bar(1) = 1
bar(0) = 0
Exception in thread "main" java.lang.NullPointerException
at Test.bar(Test.java:23)
at Test.runTest(Test.java:30)
at Test.main(Test.java:36)
Can you explain this behaviour?
你能解释一下这种行为吗?
Update
更新
Thank you very much for the many clarifying answers. I was a bit worried because this example did not correspond to my intuition. One thing that disturbed me was that a null was being converted to an int and I was wondering what the result would be: 0 like in C++? That would hae been very strange. Good that the conversion is not possible at runtime (null pointer exception).
非常感谢您的许多澄清答案。我有点担心,因为这个例子不符合我的直觉。令我不安的一件事是 null 被转换为 int,我想知道结果会是什么:像 C++ 中的 0?那会很奇怪。好的是在运行时无法进行转换(空指针异常)。
采纳答案by Jesper
Let's look at the line:
让我们看看这条线:
return y == null ? null : y.intValue();
In a ? :
statement, both sides of the :
must have the same type. In this case, Java is going to make it have the type Integer
. An Integer
can be null
, so the left side is ok. The expression y.intValue()
is of type int
, but Java is going to auto-box this to Integer
(note, you could just as well have written y
which would have saved you this autobox).
在? :
声明中, 的两边:
必须具有相同的类型。在这种情况下,Java 将使其具有类型Integer
。一种Integer
可能是null
,所以左侧是确定的。该表达式y.intValue()
的类型为int
,但 JavaInteger
会将其自动装箱到(注意,您也可以编写y
它可以为您保存此自动装箱)。
Now, the result has to be unboxed again to int
, because the return type of the method is int
. If you unbox an Integer
that is null
, you get a NullPointerException
.
现在,结果必须再次拆箱为int
,因为该方法的返回类型是int
。如果您拆箱的Integer
是null
,你会得到一个NullPointerException
。
Note: Paragraph 15.25of the Java Language Specification explains the exact rules for type conversions with regard to the ? :
conditional operator.
注意:Java 语言规范的第 15.25 段解释了有关? :
条件运算符的类型转换的确切规则。
回答by Bozho
The problem with autounboxing null
values can be really annoying. In your example it's a combination of ternary operator result type inferring and autounboxing (the JLS should be consulted why it behaves like that)
自动拆箱null
值的问题真的很烦人。在您的示例中,它是三元运算符结果类型推断和自动拆箱的组合(应咨询 JLS 为什么它的行为如此)
But generally, you should try to avoid using wrapper types. Use int
instead of Integer
. If you need a special value meaning "no result", then you can use Integer.MAX_VALUE
for example.
但通常,您应该尽量避免使用包装器类型。使用int
代替Integer
。如果您需要一个表示“没有结果”的特殊值,那么您可以使用Integer.MAX_VALUE
example。
回答by Kal
The type of the return type is inferred by Java here. That is the issue ..
返回类型的类型在这里由Java推断。这就是问题..
http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.25
http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.25
Here is the actual problem --
这是实际问题——
If one of the second and third operands is of the null type and the type of the other is a reference type, then the type of the conditional expression is that reference type.
如果第二个和第三个操作数之一是空类型而另一个的类型是引用类型,则条件表达式的类型是该引用类型。
So, basically the compiler infers the return type of the conditional expression to be Integer and thats why it allows you to compile successfully.
因此,基本上编译器将条件表达式的返回类型推断为 Integer,这就是它允许您成功编译的原因。
EDIT : See rules in comments
编辑:查看评论中的规则
回答by Dan Tao
This illustrates a problematic difference between the way a humanreads code and a compilerreads code.
这说明了人类阅读代码和编译器阅读代码的方式之间存在问题的差异。
When yousee a ternary expression, it's very possible for you to mentally split it into two parts, in the style of an if
/else
statement:
当你看到一个三元表达式时,你很可能会以if
/else
语句的风格将它分成两部分:
if (y == null)
return null;
else
return y.intValue();
Youcan see that this is invalid, as it results in a possible branch where a method defined to return an int
is actually returning null
(illegal!).
您可以看到这是无效的,因为它会导致一个可能的分支,其中定义为返回 an 的int
方法实际上正在返回null
(非法!)。
What the compilersees is an expression, which must have a type. It notes that the ternary operation includes a null
on one side and an int
on the other; due to Java's autoboxing behavior, it then comes up with a "best guess" (my term, not Java's) as to what the expression's type is: Integer
(this is fair: it's the only type which could legally be null
or a boxed int
).
什么编译器看到的是一个表达式,它必须有一个类型。它指出,三元运算包括null
一侧的a和另一侧的a int
;由于 Java 的自动装箱行为,然后它会提出一个关于表达式类型是什么的“最佳猜测”(我的术语,不是 Java 的):(Integer
这是公平的:它是唯一可以合法null
或装箱的类型int
)。
Since the method is supposed to return an int
, this is fine from the compiler's perspective: the expression being returned evaluates to an Integer
, which can be unboxed automatically.
由于该方法应该返回 an int
,因此从编译器的角度来看这很好:返回的表达式的计算结果为 an Integer
,它可以自动拆箱。
回答by michaelgulak
Guavahas a pretty elegant solution for this using MoreObjects.firstNonNull
:
番石榴为此使用了一个非常优雅的解决方案MoreObjects.firstNonNull
:
Integer someNullInt = null;
int myInt = MoreObjects.firstNonNull(someNullInt, 0);
回答by Hasan Ammori
Just in case you don't have Guava in your project, but already using Apache Commons, you might utilize Apache Lang3with its ObjectUtilsclass.
以防万一您的项目中没有 Guava,但已经在使用 Apache Commons,您可以使用Apache Lang3及其ObjectUtils类。
The usage is basically the same as Guava:
用法和Guava基本一样:
Integer number = null;
int notNull = ObjectUtils.firstNonNull(number, 0);
Note, that this method in Guava library works faster, than in Apache. Here is a short comparison I just made on my laptop (Core i7-7500U 2.7 GHz), Oracle Java 8, multiple runs, JVM preheated, results are averaged:
请注意,与在 Apache 中相比,Guava 库中的此方法运行速度更快。这是我刚刚在我的笔记本电脑(Core i7-7500U 2.7 GHz)上进行的简短比较,Oracle Java 8,多次运行,JVM 预热,结果取平均值:
╔══════════════╦══════╦══════╦════════╦══════╗
║ Library/Runs ║ 1000 ║ 1mln ║ 100mln ║ 1bln ║
╠══════════════╬══════╬══════╬════════╬══════╣
║ Apache ║ 1 ║ 30 ║ 782 ║ 9981 ║
║ Guava ║ 1 ║ 22 ║ 120 ║ 828 ║
╚══════════════╩══════╩══════╩════════╩══════╝
Results are in milliseconds. I don't think you often need to run this method for billions of times, but still, it is always good to have performance comparison
结果以毫秒为单位。我不认为你经常需要运行这个方法数十亿次,但是,有性能比较总是好的