为什么在Java中比较Integer和int会抛出NullPointerException?
观察这种情况让我感到非常困惑:
Integer i = null;
String str = null;
if (i == null) { //Nothing happens
...
}
if (str == null) { //Nothing happens
}
if (i == 0) { //NullPointerException
...
}
if (str == "0") { //Nothing happens
...
}
所以,因为我认为首先执行装箱操作(即java尝试从null
中提取int值)并且比较操作具有较低的优先级,这就是异常的原因抛出。
问题是:为什么在Java中要这样实现呢?为什么拳击比参考文献的优先级更高?或者为什么他们不在装箱前对 null
实施验证?
目前,当使用包装原语抛出 NullPointerException 时,与使用 true 对象类型抛出时,它看起来不一致。
It was very confusing to me to observe this situation:
Integer i = null;
String str = null;
if (i == null) { //Nothing happens
...
}
if (str == null) { //Nothing happens
}
if (i == 0) { //NullPointerException
...
}
if (str == "0") { //Nothing happens
...
}
So, as I think boxing operation is executed first (i.e. java tries to extract int value from null
) and comparison operation has lower priority that's why the exception is thrown.
The question is: why is it implemented in this way in Java? Why boxing has higher priority then comparing references? Or why didn't they implemented verification against null
before boxing?
At the moment it looks inconsistent when NullPointerException
is thrown with wrapped primitives and is not thrown with true object types.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
简短回答
关键点是:
==
始终是引用比较Integer
和String
,您需要使用equals
来代替equals
而不是==
引用类型和数字基元类型始终是数字比较null
总是抛出NullPointerException
String
有很多特殊处理,但实际上它不是原始类型上述语句适用于任何给定的有效 Java 代码。有了这种理解,您提供的代码片段就不会存在任何不一致之处。
长答案
以下是相关的 JLS 部分:
这解释了以下内容:
两个操作数都是引用类型,这就是
==
是引用相等比较的原因。这也解释了以下内容:
要使
==
数值相等,至少有一个操作数必须是数值类型:这解释了:
这是Effective Java 第二版,第 49 项:更喜欢原语而不是盒装原语的摘录:
在某些地方,您别无选择,只能使用装箱基元,例如泛型,但除此之外,您应该认真考虑使用装箱基元的决定是否合理。
参考文献
Integer
类型转换为int
类型”r
为null
,则拆箱转换会抛出NullPointerException
”==
和!=
==
和!=
相关问题
整数
时是否会发生自动拆箱?== 但不是
equals()
?相关问题
int num = Integer.getInteger("123")
抛出NullPointerException
? (!!!)String.equals
与==
The Short Answer
The key point is this:
==
between two reference types is always reference comparisonInteger
andString
, you'd want to useequals
instead==
between a reference type and a numeric primitive type is always numeric comparisonnull
always throwsNullPointerException
String
, it is in fact NOT a primitive typeThe above statements hold for any given valid Java code. With this understanding, there is no inconsistency whatsoever in the snippet you presented.
The Long Answer
Here are the relevant JLS sections:
This explains the following:
Both operands are reference types, and that's why the
==
is reference equality comparison.This also explains the following:
For
==
to be numerical equality, at least one of the operand must be a numeric type:This explains:
Here's an excerpt from Effective Java 2nd Edition, Item 49: Prefer primitives to boxed primitives:
There are places where you have no choice but to use boxed primitives, e.g. generics, but otherwise you should seriously consider if a decision to use boxed primitives is justified.
References
Integer
to typeint
"r
isnull
, unboxing conversion throws aNullPointerException
"==
and!=
==
and!=
Related questions
Integers
in Java does auto-unboxing occur?==
but notequals()
?Related questions
int num = Integer.getInteger("123")
throwNullPointerException
? (!!!)String.equals
versus==
由于自动装箱,您的 NPE 示例与此代码等效:
if ( i.intValue( ) == 0 )
因此,如果
i
为 NPE空
。Your NPE example is equivalent to this code, thanks to autoboxing:
if ( i.intValue( ) == 0 )
Hence NPE if
i
isnull
.i 是一个 Integer,0 是一个 int,所以真正完成的事情是这样的
,这会导致 nullPointer,因为 i 是 null。对于String我们没有这个操作,这就是为什么那里也不例外。
i is an Integer and the 0 is an int so in the what really is done is something like this
And this cause the nullPointer because the i is null. For String we do not have this operation, thats why is no exception there.
Java 的创建者可以定义
==
运算符来直接作用于不同类型的操作数,在这种情况下给出Integer I; int i;
比较I==i;
可能会问这样的问题:“I
是否持有对一个Integer
的引用,其值是i
?”——即使I
为空,也可以毫无困难地回答这个问题。不幸的是,Java 并不直接检查不同类型的操作数是否相等;相反,它检查语言是否允许将任一操作数的类型转换为另一个操作数的类型,如果允许,则将转换后的操作数与未转换的操作数进行比较。这种行为意味着对于具有某些类型组合的变量x
、y
和z
,可能有x==y
和y==z
但x!=z
[例如 x=16777216f y=16777216 z=16777217]。它还意味着比较I==i
被翻译为“将 I 转换为int
,如果没有引发异常,则将其与进行比较我
。”The makers of Java could have defined the
==
operator to directly act upon operands of different types, in which case givenInteger I; int i;
the comparisonI==i;
could ask the question "DoesI
hold a reference to anInteger
whose value isi
?"--a question which could be answered without difficulty even whenI
is null. Unfortunately, Java does not directly check whether operands of different types are equal; instead, it checks whether the language allows the type of either operand to be converted to the type of the other and--if it does--compares the converted operand to the non-converted one. Such behavior means that for variablesx
,y
, andz
with some combinations of types, it's possible to havex==y
andy==z
butx!=z
[e.g. x=16777216f y=16777216 z=16777217]. It also means that the comparisonI==i
is translated as "Convert I to anint
and, if that doesn't throw an exception, compare it toi
."这是因为 Java 的自动装箱功能。编译器检测到,在比较的右侧,您正在使用原始整数,并且还需要将包装器 Integer 值拆箱为原始 int 值。
由于这是不可能的(如您所列,它为 null),因此会抛出 NullPointerException 。
It's because of Javas autoboxing feature. The compiler detects, that on the right hand side of the comparison you're using a primitive integer and needs to unbox the wrapper Integer value into a primitive int value as well.
Since that's not possible (it's null as you lined out) the
NullPointerException
is thrown.在
i == 0
中,Java将尝试自动拆箱并进行数值比较(即“存储在i
引用的包装对象中的值是否与值0
?”)。由于
i
为null
,拆箱将抛出NullPointerException
。推理是这样的:
的第一句JLS § 15.21.1 数值相等运算符 == 和 != 如下所示:
显然,
i
可转换为数字类型,而0
是数字类型,因此对操作数执行二进制数字提升。§ 5.6.2 二进制数字提升 说(除其他外):
§ 5.1.8 拆箱转换 说(除其他事项外):
In
i == 0
Java will try to do auto-unboxing and do a numerical comparison (i.e. "is the value stored in the wrapper object referenced byi
the same as the value0
?").Since
i
isnull
the unboxing will throw aNullPointerException
.The reasoning goes like this:
The first sentence of JLS § 15.21.1 Numerical Equality Operators == and != reads like this:
Clearly
i
is convertible to a numeric type and0
is a numeric type, so the binary numeric promotion is performed on the operands.§ 5.6.2 Binary Numeric Promotion says (among other things):
§ 5.1.8 Unboxing Conversion says (among other things):
只需编写一个方法并调用它即可避免 NullPointerException。
Simply write a method and call it to avoid NullPointerException.