Programing

equals (null) 대신 NullPointerException이 발생하면 나쁜 생각입니까?

crosscheck 2020. 10. 19. 07:45
반응형

equals (null) 대신 NullPointerException이 발생하면 나쁜 생각입니까?


의 계약 equals에 관해서 null으로 다음입니다 :

null이 아닌 참조 값의 x경우 x.equals(null)이어야합니다 return false.

이는 다소 특이한 데,이면 다음 o1 != nullo2 == null같습니다.

o1.equals(o2) // returns false
o2.equals(o1) // throws NullPointerException

사실 o2.equals(o1) throws NullPointerException은 프로그래머 오류로 우리를 경고하기 때문에, 좋은 것입니다. 하지만 여러 가지 이유로 오류를으로 전환하면 오류가 포착되지 o1.equals(o2)않고 대신 "조용히 실패"합니다.

따라서 질문은 다음과 같습니다.

  • 던지는 대신 o1.equals(o2)해야하는 return false것이 좋은 생각 인 이유는 무엇 NullPointerException입니까?
  • 가능한 한 계약을 다시 작성하여 anyObject.equals(null)항상 NullPointerException대신 던진 다면 나쁜 생각 일까요?

비교 Comparable

이와 대조적으로 Comparable계약 내용 은 다음과 같습니다.

참고 null모든 클래스의 인스턴스가 아닌, 그리고 e.compareTo(null)던져해야 NullPointerException하지만, 심지어 e.equals(null)반환 false.

NullPointerException에 적합 하다면 compareTo왜 그렇지 equals않습니까?

관련 질문


순전히 의미 론적 주장

다음은 Object.equals(Object obj)문서 의 실제 단어입니다 .

다른 개체 가이 개체 와 "같은" 지 여부를 나타냅니다 .

그리고 객체는 무엇입니까?

JLS 4.3.1 객체

객체 A는 클래스 인스턴스 또는 배열.

참조 값 (종종 참조 )은 이러한 개체에 대한 포인터이며, 개체 null참조하지 않는 특수 참조 입니다.

이 각도에서 내 주장은 정말 간단합니다.

  • equals다른 개체 가 "같음" 인지 테스트this
  • null참조는 테스트에 대한 다른 개체제공하지 않습니다.
  • 따라서 equals(null)던져야합니다NullPointerException

이 비대칭이 일치하지 않는지에 대한 질문에 대해서는 그렇지 않다고 생각합니다.

  • 어느 남자에게 그가 다음 남자만큼 좋은지 물어 보면 각자 예라고 대답 할 것입니다.
  • 누구에게도 그가 아무도 아닌지 물어보십시오.
  • 아무에게도 남자만큼 좋은지 물어 보면 답장을받지 못할 것입니다.

그 순간 컴파일러는 깨달음을 얻었습니다.


예외는 정말 예외적 인 상황 이어야합니다 . 널 포인터는 프로그래머 오류가 아닐 수 있습니다.

기존 계약을 인용했습니다. 관례에 어긋나기로 결정했다면, 모든 Java 개발자가 동등하게 false를 반환 할 것으로 예상 할 때 예상치 못한 일을하고 반갑지 않은 일을하게되어 클래스를 패 리아로 만들 것입니다.

나는 더 이상 동의 할 수 없었다. 나는 항상 예외를 던지기 위해 equals를 다시 작성하지 않을 것입니다. 내가 클라이언트라면 그렇게 한 모든 클래스를 교체 할 것입니다.


.equals가 ==와 어떻게 관련되어 있고 .compareTo가 비교 연산자>, <,> =, <=와 관련되어 있는지 생각해보십시오.

.equals를 사용하여 객체를 null과 비교하는 것이 NPE를 던져야한다고 주장하려면이 코드도 하나를 던져야한다고 말해야합니다.

Object o1 = new Object();
Object o2 = null;
boolean b = (o1 == o2); // should throw NPE here!

o1.equals (o2)와 o2.equals (o1)의 차이점은 첫 번째 경우에는 o1 == o2와 유사한 무언가를 null과 비교하는 반면 두 번째 경우 에는 equals 메서드가 실제로 실행되지 않는다는 것입니다. 그래서 전혀 비교가 일어나지 않습니다.

.compareTo 계약과 관련하여 null이 아닌 개체를 null 개체와 비교하는 것은 다음과 같이 시도하는 것과 같습니다.

int j = 0;
if(j > null) { 
   ... 
}

분명히 이것은 컴파일되지 않을 것입니다. 자동 언 박싱을 사용하여 컴파일 할 수 있지만 비교를 수행 할 때 NPE를 얻습니다. 이는 .compareTo 계약과 일치합니다.

Integer i = null;
int j = 0;
if(j > i) { // NPE
   ... 
}

이것이 반드시 귀하의 질문에 대한 대답이 아니라, 현재의 행동이 유용하다는 것을 알게 된 경우의 예일뿐입니다.

private static final String CONSTANT_STRING = "Some value";
String text = getText();  // Whatever getText() might be, possibly returning null.

그대로 나는 할 수있다.

if (CONSTANT_STRING.equals(text)) {
    // do something.
}

그리고 NullPointerException이 발생할 가능성이 없습니다. 제안한대로 변경된 경우 다음을 수행해야합니다.

if (text != null && text.equals(CONSTANT_STRING)) {
    // do something.
}

이것은 행동이있는 그대로의 충분한 이유인가 ?? 잘 모르겠지만 유용한 부작용입니다.


객체 지향 개념을 고려하고 전체 발신자 및 수신자 역할을 고려한다면 행동이 편리하다고 말하고 싶습니다. 첫 번째 경우에 당신은 그가 아무도 같지 않은지 물어 보는 것입니다. 그는 "아니요, 아니에요"라고 말해야합니다.

하지만 두 번째 경우에는 아무에게도 언급하지 않았으므로 실제로 아무에게도 요구하지 않습니다. 이것은 예외를 던져야하고, 첫 번째 경우는 그렇지 않아야합니다.

객체 방향을 잊어 버리고 표현을 수학적 동등성으로 취급하는 경우에만 비대칭이라고 생각합니다. 그러나이 패러다임에서는 양측이 서로 다른 역할을하므로 순서가 중요 할 것으로 예상된다.

As one final point. A null pointer exception should be raised when there's an error in your code. However, Asking an object if he is nobody, shouldn't be considered a programming flaw. I think it's perfectly ok to ask an object if he isn't null. What if you don't control the source that provides you with the object? and this source sends you null. Would you check if the object is null and only afterwards see if they are equals? Wouldn't it be more intuitive to just compare the two and whatever the second object is the comparison will be carried out without exceptions?

In all honesty, I would be pissed if an equals method within its body returns a null pointer exception on purpose. Equals is meant to be used against any sort of object, so it shouldn't be so picky on what it receives. If an equals method returned npe, the last thing on my mind would be that it did that on purpose. Specially considering it's an unchecked exception. IF you did raise an npe a guy would have to remember to always check for null before calling your method, or even worse, surround the call to equals in a try/catch block (God I hate try/catch blocks) But oh well...


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.

If the NullPointerException was used as you suggest and you tried the (sort of pointless) operation of...

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.


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.

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.


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.

As for why null.equals(y) is different, it is a programming error to call any instance 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).

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.

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.

It could have 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.


Note that the contract is "for any non-null reference x". So the implementation will look like:

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:

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;
}

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.

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.


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.

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 :))

But this requirement does make a strange and non symmetric equals relation.

참고URL : https://stackoverflow.com/questions/2887761/is-it-a-bad-idea-if-equalsnull-throws-nullpointerexception-instead

반응형