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?


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

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


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


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ą ==.


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.


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.


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.


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.


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.


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ą!


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.


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

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

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


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 !!!!


-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.


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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.