Java null sprawdź, dlaczego używasz == zamiast .equals ()

125

W Javie powiedziano mi, że podczas sprawdzania wartości null należy używać == zamiast .equals (). Jakie są tego przyczyny?

Jim Jeffries
źródło
12
Najłatwiej jest sprawdzić wartość null equals()i zobaczyć. Kiedy spróbujesz, będzie to oczywiste
Goran Jovic
Nawiasem mówiąc, wyszukiwanie google ze słowami kluczowymi „java null check” (bez cudzysłowów) dało mi jako jedno z najpopularniejszych trafień w tym wątku , który zawiera te same informacje, co odpowiedzi tutaj.
Mitch Schwartz

Odpowiedzi:

179

To dwie zupełnie różne rzeczy. ==porównuje odniesienie do obiektu, jeśli istnieje, zawarte w zmiennej. .equals()sprawdza, czy dwa obiekty są równe zgodnie z ich umową, co oznacza równość. Jest całkowicie możliwe, aby dwie różne instancje obiektów były „równe” zgodnie z ich umową. A potem jest drobny szczegół, ponieważ equalsjest to metoda, jeśli spróbujesz wywołać ją w nullodwołaniu, otrzymasz plik NullPointerException.

Na przykład:

class Foo {
    private int data;

    Foo(int d) {
        this.data = d;
    }

    @Override
    public boolean equals(Object other) {
        if (other == null || other.getClass() != this.getClass()) {
           return false;
        }
        return ((Foo)other).data == this.data;
    }

    /* In a real class, you'd override `hashCode` here as well */
}

Foo f1 = new Foo(5);
Foo f2 = new Foo(5);
System.out.println(f1 == f2);
// outputs false, they're distinct object instances

System.out.println(f1.equals(f2));
// outputs true, they're "equal" according to their definition

Foo f3 = null;
System.out.println(f3 == null);
// outputs true, `f3` doesn't have any object reference assigned to it

System.out.println(f3.equals(null));
// Throws a NullPointerException, you can't dereference `f3`, it doesn't refer to anything

System.out.println(f1.equals(f3));
// Outputs false, since `f1` is a valid instance but `f3` is null,
// so one of the first checks inside the `Foo#equals` method will
// disallow the equality because it sees that `other` == null
TJ Crowder
źródło
masz na myśli public int data?
Jé Queue
@Xepoch: Nie, generalnie nie tworzę pól publicznych (chociaż tak naprawdę nie ma to znaczenia w tym przykładzie). Czemu?
TJ Crowder
@TJ Crowder "To dwie zupełnie różne rzeczy ..." ogólnie tak. Jednak domyślna implementacja obu jest taka sama, jeśli moje rozumienie jest poprawne. Patrząc na kod źródłowy, .equals () w zasadzie sprawdza ==. hg.openjdk.java.net/jdk7/jdk7/jdk/file/tip/src/share/classes/…
Ayush
1
@Ayush - to jest domyślne ustawienie Object, tak. Jest jednak zastępowany przez dużą liczbę klas JDK. Ale nie chodzi o implementację, chodzi o semantykę. (Nota boczna: JDK7 jest bardzo nieaktualny.)
TJ Crowder
Racja, to ma sens, chciałem tylko wyjaśnić.
Ayush
38

jeśli powołać .equals()na nulldostanieszNullPointerException

Dlatego zawsze zaleca się sprawdzenie nieważności przed wywołaniem metody, gdziekolwiek ma to zastosowanie

if(str!=null && str.equals("hi")){
 //str contains hi
}  

Zobacz także

Jigar Joshi
źródło
34
Twój przykład jest ogólnie lepiej napisany jako if ("hi".equals(str)).
ColinD
3
@ user368186: nie chodzi o to, czy metoda equals obejmuje sprawdzenie wartości null. Jeśli odwołanie do obiektu ma wartość null, wywołanie someObject.equals(null)wywoła a NullPointerExceptionbez wprowadzania metody equals.
Dave Costa
2
@ColinD Zgadzam się, tylko pokazuję tutaj
Jigar Joshi
2
Zawsze zaleca się unikanie wartości null za wszelką cenę, więc w ogóle nie potrzebujesz sprawdzania wartości null;).
fwielstra
2
Zawsze możesz użyć Objects.equals(a, b)It nie zgłosi wyjątku NullPointerException, ale nadal zależy to od metody "równej" metody "a" i "b"
Dominik Minc
29

Oprócz zaakceptowanej odpowiedzi ( https://stackoverflow.com/a/4501084/6276704 ):

Od Java 1.7, jeśli chcesz porównać dwa obiekty, które mogą być zerowe, polecam tę funkcję:

Objects.equals(onePossibleNull, twoPossibleNull)

java.util.Objects

Ta klasa składa się ze statycznych metod narzędziowych do wykonywania operacji na obiektach. Te narzędzia obejmują metody null-safe lub null-tolerant do obliczania kodu skrótu obiektu, zwracania ciągu dla obiektu i porównywania dwóch obiektów.

Od: 1.7

Niebieski
źródło
2
Aby uczynić go bardziej widocznym dla innych (patrz odpowiedź chin90 lub JavaDoc ): Objects.equals(null, null)powróci true- miej to na uwadze.
Thomas
20

W Javie 0 lub null to typy proste, a nie obiekty.

Metoda equals () nie jest tworzona dla typów prostych. Proste typy można dopasować za pomocą ==.

user523859
źródło
4
głosuj za właściwą odpowiedź, która jest najbardziej użyteczna, w przeciwieństwie do oczywistej odpowiedzi „NullPointerException zostanie zwrócona” herp derp.
volk
4
foo.equals(null)

Co się stanie, jeśli foo jest zerowe?

Otrzymasz NullPointerException.

Nick Orton
źródło
3

Jeśli zmienna Object ma wartość null, nie można wywołać na niej metody equals (), dlatego poprawne jest sprawdzenie odwołania do obiektu null.

Jé Queue
źródło
2

Jeśli spróbujesz wywołać equals w odwołaniu do obiektu o wartości null, zostanie zgłoszony wyjątek wskaźnika o wartości null.

JESTEM
źródło
2

Według źródeł nie ma znaczenia, czego użyć do domyślnej implementacji metody:

public boolean equals(Object object) {
    return this == object;
}

Ale nie możesz być tego pewien equalsw klasie niestandardowej.

DixonD
źródło
Ma to znaczenie, ponieważ equalsmoże tylko zwrócić falselub spowodować a NullPointerException(lub coś innego, jeśli zastąpiona equalsmetoda jest nonsensowna).
Tom
2

Jeśli użyjemy metody => .equals

if(obj.equals(null))  

// Which mean null.equals(null) when obj will be null.

Gdy twój obiekt będzie zerowy, zgłosi wyjątek punktu zerowego.

więc powinniśmy użyć ==

if(obj == null)

porówna referencje.

AKT
źródło
2

Object.equals jest null bezpieczny, należy jednak pamiętać, że jeśli dwa obiekty są puste, object.equals zwróci wartość true, więc przed użyciem object.equals dla porównanie.

String firstname = null;
String lastname = null;

if(Objects.equals(firstname, lastname)){
    System.out.println("equal!");
} else {
    System.out.println("not equal!");
}

Przykładowy fragment powyżej zwróci wartość równą!

podbródek 90
źródło
Jak stwierdzono w JavaDoc (zawsze mądrze jest je przeczytać): Consequently, if both arguments are null, true is returned. ...:)
Thomas
1

Ponieważ equal to funkcja wywodząca się z klasy Object, funkcja ta porównuje elementy tej klasy. jeśli użyjesz go z null, zwróci false, ponieważ zawartość klasy nie jest pusta. Dodatkowo == porównuje odniesienie do obiektu.

danny.lesnik
źródło
Cóż, wynik może być tylko falselub NullPointerException(jeśli equalsnie zostanie zastąpiony czymś złym).
Tom
1

tutaj jest przykład gdzie, str != nullale str.equals(null)podczas używaniaorg.json

 JSONObject jsonObj = new JSONObject("{field :null}");
 Object field = jsonObj.get("field");
 System.out.println(field != null);        // => true
 System.out.println( field.equals(null)); //=> true
 System.out.println( field.getClass());  // => org.json.JSONObject$Null




EDYCJA: oto klasa org.json.JSONObject $ Null :

/**
 * JSONObject.NULL is equivalent to the value that JavaScript calls null,
 * whilst Java's null is equivalent to the value that JavaScript calls
 * undefined.
 */
private static final class Null {

    /**
     * A Null object is equal to the null value and to itself.
     *
     * @param object
     *            An object to test for nullness.
     * @return true if the object parameter is the JSONObject.NULL object or
     *         null.
     */
    @Override
    public boolean equals(Object object) {
        return object == null || object == this;
    }  
}
dina
źródło
Problem polega na tym, że field.equals(null)zwraca prawdę. To łamie zwykłe zachowanie Javy i dlatego jest mylące. To powinno działać field.equals("null"), przynajmniej z mojego punktu widzenia. Nie wiem, dlaczego programiści biblioteki pomyśleli, że warto byłoby to wspierać.
Tom
Przy okazji, Twoje pierwsze zdanie zawiera błędy gramatyczne i nie jest jasne, co masz na myśli. Czy masz na myśli „Oto przykład, gdzie str != nulli str.equals(null)powrócić truepodczas korzystania z org.json .”?
Tom
Myślę, że to dlatego, że jsonObjectzawiera klucz "field", dlatego fieldnie jest pusty, ma odniesienie, które zawiera json.org.JSONObject$Null obiekt
dina
Tak, ale nie traktowałbym Nulljak nulli "null"zamiast tego używałbym . Ale myślę, że zrobili to, aby uniknąć wymagania Stringsa. Ale nawet z tego lib, field.equals(null)to nadal niemal zawsze problem: P.
Tom
0

Dlatego nigdy się nie mylę i unikam problemów z tym rozwiązaniem:

if(str.trim().length() <=0 ) {
   // is null !
}
Matheus Marques
źródło
5
Jeśli str jest null, będzie to NPE
typoerrpr
Dodatkowo pusty ciąg ( ""o długości 0) jest czymś zupełnie innym niż nullreferencja (tj. Brak łańcucha).
Thomas
0

Spotkałem się z tą sprawą zeszłej nocy.
Ustalam, że po prostu:

Nie istnieje metoda equals () dla null
Więc nie możesz wywołać nieistniejącej metody jeśli nie masz
- >>> To jest powód dlaczego używamy == do sprawdzenia null

Neo_
źródło
0

Twój kod łamie prawo Demeter. Dlatego lepiej zreformować sam projekt. Aby obejść ten problem, możesz użyć opcjonalnego

   obj = Optional.ofNullable(object1)
    .map(o -> o.getIdObject11())
    .map(o -> o.getIdObject111())
    .map(o -> o.getDescription())
    .orElse("")

powyżej służy do sprawdzenia hierarchii obiektu, więc po prostu użyj

Optional.ofNullable(object1) 

jeśli masz tylko jeden obiekt do sprawdzenia

Mam nadzieję że to pomoże !!!!

Akitha_MJ
źródło
-3

Zawsze możesz to zrobić

if (str == null || str.equals(null))

Spowoduje to najpierw sprawdzenie odwołania do obiektu, a następnie sprawdzenie samego obiektu, podając, że odwołanie nie jest null.

Kevin Orriss
źródło
if (str == null || str.equals (null) || str.equals (""))
Lou Morda
Wykorzystałem twoją odpowiedź i dodałem czek na pusty ciąg! jeśli się nie mylę, null i „” to nie to samo.
Lou Morda,
4
Czy dodawanie drugiego sprawdzenia pod kątem wartości null nie jest całkowicie zbędne?
Justin Rowe
2
@JustinRowe To jest nie tylko zbędne, ale także bardzo złe. Proszę, nigdy nie rób czegoś takiego x.equals(null).
Tom
@Tom, JustinRowe proszę zobaczyć moją odpowiedź wyżej, dlaczego nie jest to zbędne, ani kompletne śmieci stackoverflow.com/questions/4501061/...
Dina