Java 如果 equals(null) 抛出 NullPointerException 是不是一个坏主意?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2887761/
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
Is it a bad idea if equals(null) throws NullPointerException instead?
提问by polygenelubricants
The contract of equals
with regards to null
, is as follows:
equals
关于null
,的合同如下:
For any non-null reference value
x
,x.equals(null)
shouldreturn false
.
对于任何非空引用值
x
,x.equals(null)
应该return false
。
This is rather peculiar, because if o1 != null
and o2 == null
, then we have:
这是相当奇特的,因为如果o1 != null
和o2 == null
,那么我们有:
o1.equals(o2) // returns false
o2.equals(o1) // throws NullPointerException
The fact that o2.equals(o1) throws NullPointerException
is a good thing, because it alerts us of programmer error. And yet, that error would not be catched if for various reasons we just switched it around to o1.equals(o2)
, which would just "silently fail" instead.
这o2.equals(o1) throws NullPointerException
是一件好事,因为它提醒我们程序员的错误。然而,如果出于各种原因我们只是将其切换到o1.equals(o2)
,则不会捕获该错误,而这只会“默默地失败”。
So the questions are:
所以问题是:
- Why is it a good idea that
o1.equals(o2)
shouldreturn false
instead of throwingNullPointerException
? - Would it be a bad idea if wherever possible we rewrite the contract so that
anyObject.equals(null)
always throwNullPointerException
instead?
- 为什么
o1.equals(o2)
应该return false
而不是扔是个好主意NullPointerException
? - 如果我们尽可能地重写合同以便
anyObject.equals(null)
总是抛出,这是NullPointerException
不是一个坏主意?
On comparison with Comparable
与 Comparable
In contrast, this is what the Comparable
contractsays:
相比之下,Comparable
合同是这样写的:
Note that
null
is not an instance of any class, ande.compareTo(null)
should throw aNullPointerException
even thoughe.equals(null)
returnsfalse
.
请注意,
null
它不是任何类的实例,即使返回也e.compareTo(null)
应该抛出一个。NullPointerException
e.equals(null)
false
If NullPointerException
is appropriate for compareTo
, why isn't it for equals
?
如果NullPointerException
适合compareTo
,为什么不适合equals
?
Related questions
相关问题
A purely semantical argument
纯语义论证
These are the actual words in the Object.equals(Object obj)
documentation:
这些是Object.equals(Object obj)
文档中的实际文字:
Indicates whether some other objectis "equal to" this one.
指示其他某个对象是否“等于”这个对象。
And what is an object?
什么是对象?
JLS 4.3.1 Objects
JLS 4.3.1 对象
An objectis a class instanceor an array.
The reference values (often just references) are pointers to these objects, and a special
null
reference, which refers to no object.
一个对象是一个类实例或一个数组。
引用值(通常只是引用)是指向这些对象的指针,以及一个特殊的
null
引用,它不引用任何对象。
My argument from this angle is really simple.
我从这个角度的论点非常简单。
equals
tests whether some other objectis "equal to"this
null
reference gives no other objectfor the test- Therefore,
equals(null)
should throwNullPointerException
equals
测试其他对象是否“等于”this
null
参考没有为测试提供其他对象- 因此,
equals(null)
应该抛出NullPointerException
回答by duffymo
An exception really should be an exceptionalsituation. A null pointer might not be a programmer error.
一个例外真的应该是一个例外的情况。空指针可能不是程序员错误。
You quoted the existing contract. If you decide to go against convention, after all this time, when every Java developer expects equals to return false, you'll be doing something unexpected and unwelcome that will make your class a pariah.
您引用了现有合同。如果您决定违反惯例,那么在所有 Java 开发人员都希望 equals 返回 false 之后,您将做一些意想不到和不受欢迎的事情,这将使您的班级成为贱民。
I could't disagree more. I would not rewrite equals to throw an exception all the time. I'd replace any class that did that if I were its client.
我不能同意更多。我不会重写等于一直抛出异常。如果我是它的客户,我会替换任何这样做的类。
回答by Rob L
Personally, I'd rather it perform as it does.
就我个人而言,我更喜欢它的表现。
The NullPointerException
identifies that the problem is in the object against which the equals operation is being performed.
的NullPointerException
标识,这个问题是在与正在执行equals操作的对象。
If the NullPointerException
was used as you suggest and you tried the (sort of pointless) operation of...
如果NullPointerException
按照您的建议使用并且您尝试了(有点无意义的)操作...
o1.equals(o1)
where o1= null...
Is the NullPointerException
thrown because your comparison function is screwed or because o1 is null but you didn't realise?
An extreme example, I know, but with current behaviour I feel you can tell easily where the problem lies.
o1.equals(o1)
where o1= null...NullPointerException
抛出是因为你的比较函数被搞砸了还是因为 o1 为空但你没有意识到?一个极端的例子,我知道,但根据目前的行为,我觉得你可以很容易地看出问题出在哪里。
回答by DaveJohnston
Not that this is neccessarily an answer to your question, it is just an example of when I find it useful that the behaviour is how it is now.
并不是说这一定是您问题的答案,这只是我发现行为是现在的样子很有用的一个例子。
private static final String CONSTANT_STRING = "Some value";
String text = getText(); // Whatever getText() might be, possibly returning null.
As it stands I can do.
就目前而言,我可以做到。
if (CONSTANT_STRING.equals(text)) {
// do something.
}
And I have no chance of getting a NullPointerException. If it were changed as you suggested, I would be back to having to do:
而且我没有机会获得 NullPointerException。如果按照您的建议进行更改,我将不得不重新执行以下操作:
if (text != null && text.equals(CONSTANT_STRING)) {
// do something.
}
Is this a good enough reason for the behaviour to be as it is?? I don't know, but it is a useful side-effect.
这是行为保持现状的充分理由吗?我不知道,但这是一个有用的副作用。
回答by Anton
This is a tricky question. For backward compatability you can't do so.
这是一个棘手的问题。为了向后兼容,你不能这样做。
Imagine the following scenario
想象以下场景
void m (Object o) {
if (one.equals (o)) {}
else if (two.equals (o)) {}
else {}
}
Now with equals returning false else clause will get executed, but not when throwing an exception.
现在使用 equals 返回 false else 子句将被执行,但不会在抛出异常时执行。
Also null is not really equal to say "2" so it makes perfect sense to return false. Then it is probably better to insist null.equals("b") to return also false :))
同样 null 并不真的等于说“2”,所以返回 false 是完全合理的。那么最好坚持 null.equals("b") 也返回 false :))
But this requirement does make a strange and non symmetric equals relation.
但是这个要求确实产生了一种奇怪且非对称的相等关系。
回答by mdma
I think it's about convenience and more importantly consistency - allowing nulls to be part of the comparison avoids having to do a null
check and implement the semantics of that each time equals
is called. null
references are legal in many collection types, so it makes sense they can appear as the right side of the comparison.
我认为这是关于方便,更重要的是一致性——允许空值成为比较的一部分,避免null
每次equals
调用时都必须进行检查和实现语义。null
引用在许多集合类型中都是合法的,因此它们可以作为比较的右侧出现是有道理的。
Using instance methods for equality, comparison etc., necessarily makes the arrangement asymmetric - a little hassle for the huge gain of polymorphism. When I don't need polymorphism, I sometimes create a symmetric static method with two arguments, MyObject.equals(MyObjecta, MyObject b)
. This method then checks whether one or both arguments are null references. If I specifically want to exclude null references, then I create an additional method e.g. equalsStrict()
or similar, that does a null check before delegating to the other method.
使用实例方法进行相等、比较等,必然会使排列不对称——对于多态性的巨大收益来说有点麻烦。当我不需要多态时,我有时会创建一个带有两个参数的对称静态方法,MyObject.equals(MyObjecta, MyObject b)
. 此方法然后检查一个或两个参数是否为空引用。如果我特别想排除空引用,那么我会创建一个额外的方法,例如equalsStrict()
或类似的方法,在委托给另一个方法之前进行空检查。
回答by Vijay Mathew
Note that the contract is "for any non-null reference x". So the implementation will look like:
请注意,合同是“针对任何非空引用 x”。所以实现将如下所示:
if (x != null) {
if (x.equals(null)) {
return false;
}
}
x
need not be null
to be deemed equal to null
because the following definition of equals
is possible:
x
不必null
被视为等于,null
因为以下定义equals
是可能的:
public boolean equals(Object obj) {
// ...
// If someMember is 0 this object is considered as equal to null.
if (this.someMember == 0 and obj == null) {
return true;
}
return false;
}
回答by fastcodejava
In the first case o1.equals(o2)
returns false because o1
is not equal to o2
, which is perfectly fine. In the second case, it throws NullPointerException
because o2
is null
. One cannot call any method on a null
. It may be a limitation of programming languages in general, but we have to live with it.
在第一种情况下o1.equals(o2)
返回 false 因为o1
不等于o2
,这完全没问题。在第二种情况下,它抛出NullPointerException
因为o2
is null
。不能在null
. 总的来说,这可能是编程语言的一个限制,但我们必须忍受它。
It is also not a good idea to throw NullPointerException
you are violating the contract for the equals
method and making things more complex than it has to be.
认为NullPointerException
您违反了该equals
方法的合同并使事情变得比它必须的复杂,这也不是一个好主意。
回答by Arkku
There are many common situations where null
is not in any way exceptional, e.g. it may simply represent the (non-exceptional) case where a key has no value, or otherwise stand for “nothing”. Hence, doing x.equals(y)
with an unknown y
is also quite common, and having to always check for null
first would be just wasted effort.
有许多常见的情况null
在任何情况下都不是例外,例如它可能只是代表键没有值的(非例外)情况,或者代表“无”。因此,x.equals(y)
处理未知数y
也很常见,而必须始终先检查null
只会浪费精力。
As for why null.equals(y)
is different, it isa programming error to call anyinstance method on a null reference in Java, and therefore worthy of an exception. The ordering of x
and y
in x.equals(y)
should be chosen such that x
is known to not be null
. I would argue that in almost all cases this reordering can be done based on what is known about the objects beforehand (e.g., from their origin, or by checking against null
for other method calls).
至于为什么null.equals(y)
不同,在 Java 中调用空引用上的任何实例方法都是编程错误,因此值得例外。和in的顺序应选择为已知不是。我认为在几乎所有情况下,这种重新排序都可以根据事先对对象的了解(例如,从它们的来源,或通过检查其他方法调用)来完成。x
y
x.equals(y)
x
null
null
Meanwhile if both objects are of unknown “nullness”, then other code almost certainly requires checking at least one of them, or not much can be done with the object without risking the NullPointerException
.
同时,如果两个对象都是未知的“空值”,那么其他代码几乎肯定需要检查其中至少一个,否则在不冒NullPointerException
.
And since this is the way it is specified, it is a programming error to break the contract and raise an exception for a null
argument to equals
. And if you consider the alternative of requiring an exception to be thrown, then every implementation of equals
would have to make a special case of it, and every call to equals
with any potentially null
object would have to check before calling.
并且由于这是指定的方式,因此破坏合同并为 的null
参数引发异常是一个编程错误equals
。如果您考虑要求抛出异常的替代方案,则 的每个实现equals
都必须对其进行特殊处理,并且每次对equals
任何潜在null
对象的调用都必须在调用之前进行检查。
It couldhave been specified differently (i.e., the precondition of equals
would require the argument to be non-null
), so this is not to say that your argumentation is invalid, but the current specification makes for a simpler and more practical programming language.
它可以有不同的指定(即, 的前提条件equals
要求参数为 non- null
),所以这并不是说您的论证无效,而是当前的规范提供了一种更简单、更实用的编程语言。
回答by Sean Owen
To the question of whether this asymmetry is inconsistent, I think not, and I refer you to this ancient Zen kōan:
对于这种不对称是否不一致的问题,我认为不是,我给你参考这个古老的禅宗公案:
- Ask any man if he's as good as the next man and each will say yes.
- Ask any man if he's as good as nobody and each will say no.
- Ask nobody if it's as good as any man and you'll never get a reply.
- 问任何人他是否和下一个人一样好,每个人都会说是。
- 问任何人他是否和任何人一样好,每个人都会说不。
- 问任何人它是否和任何人一样好,你永远不会得到答复。
At that moment, the compiler reached enlightenment.
那一刻,编译器达到了启蒙。
回答by Angus
Think of how .equals is related to == and .compareTo is related to the comparison operators >, <, >=, <=.
想想 .equals 与 == 的关系,而 .compareTo 与比较运算符 >、<、>=、<= 的关系。
If you're going to argue that using .equals to compare an object to null should throw a NPE, then you'd have to say that this code should throw one as well:
如果您要争辩说使用 .equals 将对象与 null 进行比较应该抛出 NPE,那么您必须说这段代码也应该抛出 NPE:
Object o1 = new Object();
Object o2 = null;
boolean b = (o1 == o2); // should throw NPE here!
The difference between o1.equals(o2) and o2.equals(o1) is that in the first case you're comparing something to null, similar to o1 == o2, while in the second case, the equals method is never actually executedso there's no comparison happening at all.
o1.equals(o2) 和 o2.equals(o1) 之间的区别在于,在第一种情况下,您将某些内容与 null 进行比较,类似于 o1 == o2,而在第二种情况下,从未实际执行 equals 方法所以根本没有比较。
Regarding the .compareTo contract, comparing a non-null object with a null object is like trying do this:
关于 .compareTo 合同,将非空对象与空对象进行比较就像尝试这样做:
int j = 0;
if(j > null) {
...
}
Obviously this won't compile. You can use auto-unboxing to make it compile, but you get a NPE when you do the comparison, which is consistent with the .compareTo contract:
显然这不会编译。您可以使用自动拆箱使其编译,但是在进行比较时会得到一个 NPE,这与 .compareTo 合同一致:
Integer i = null;
int j = 0;
if(j > i) { // NPE
...
}