Java null controlla perché usare == invece di .equals ()


125

In Java mi è stato detto che quando si esegue un controllo nullo si dovrebbe usare == invece di .equals (). Quali sono le ragioni di ciò?


12
La cosa più semplice è provare a verificare con null equals()e vedere. Quando proverai sarà subito ovvio
Goran Jovic

A proposito, una ricerca su Google con parole chiave "java null check" (senza virgolette) mi ha dato come uno dei migliori risultati in questo thread , che ha le stesse informazioni delle risposte qui.
Mitch Schwartz,

Risposte:


179

Sono due cose completamente diverse. ==confronta l'eventuale riferimento all'oggetto contenuto in una variabile. .equals()controlla se due oggetti sono uguali in base al loro contratto per il significato di uguaglianza. È del tutto possibile che due istanze di oggetti distinti siano "uguali" in base al loro contratto. E poi c'è il dettaglio minore che poiché equalsè un metodo, se provi a invocarlo su un nullriferimento, otterrai un file NullPointerException.

Per esempio:

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

intendi public int data?
Jé Queue

@Xepoch: No, in genere non creo campi pubblici (anche se in questo esempio non ha molta importanza). Perché?
TJ Crowder

@TJ Crowder "Sono due cose completamente diverse .." in generale sì. Tuttavia, l'implementazione predefinita di entrambi è la stessa, se la mia comprensione è corretta. Guardando il codice sorgente, .equals () fondamentalmente esegue un controllo ==. hg.openjdk.java.net/jdk7/jdk7/jdk/file/tip/src/share/classes/…
Ayush

1
@Ayush - Questa è l'impostazione predefinita Object, sì. Tuttavia, è sovrascritto da un gran numero di classi JDK. Ma il punto non riguarda l'implementazione, ma la semantica. (Nota a margine: JDK7 è molto obsoleto.)
TJ Crowder il

Giusto, ha senso, volevo solo chiarire.
Ayush

38

se invocate .equals()su nullotterreteNullPointerException

Quindi è sempre consigliabile verificare la nullità prima di invocare il metodo dove si applica

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

Vedi anche


34
Il tuo esempio è generalmente scritto meglio come if ("hi".equals(str)).
ColinD

3
@ user368186: il punto non è se il metodo equals include un controllo nullo. Se il riferimento all'oggetto è nullo, la chiamata someObject.equals(null)solleverà a NullPointerExceptionsenza mai entrare nel metodo equals.
Dave Costa,

2
@ColinD D'accordo solo dimostrando qui
Jigar Joshi

2
È sempre consigliabile evitare i valori nulli a tutti i costi, quindi non è necessario alcun controllo nullo;).
fwielstra

2
Puoi sempre usarlo Objects.equals(a, b)Non solleverà NullPointerException, ma dipende comunque dal metodo "uguale" di "a" e "b"
Dominik Minc

29

Oltre alla risposta accettata ( https://stackoverflow.com/a/4501084/6276704 ):

A partire da Java 1.7, se vuoi confrontare due Oggetti che potrebbero essere nulli, ti consiglio questa funzione:

Objects.equals(onePossibleNull, twoPossibleNull)

java.util.Objects

Questa classe è costituita da metodi di utilità statici per operare sugli oggetti. Queste utilità includono metodi null-safe o null-tolerant per calcolare il codice hash di un oggetto, restituire una stringa per un oggetto e confrontare due oggetti.

Dal: 1.7


2
Solo per renderlo più visibile agli altri (vedi la risposta di chin90 o JavaDoc ): Objects.equals(null, null)tornerà true- tienilo a mente.
Thomas

20

In Java 0 o null sono tipi semplici e non oggetti.

Il metodo equals () non è costruito per i tipi semplici. I tipi semplici possono essere abbinati a ==.


4
upvote per la risposta effettiva che è più utile in contrapposizione all'ovvia "NullPointerException verrà restituita" herp derp answer.
volk

4
foo.equals(null)

Cosa succede se foo è nullo?

Ottieni una NullPointerException.


3

Se una variabile Object è nulla, non è possibile chiamare un metodo equals () su di essa, quindi un controllo del riferimento a un oggetto di null è corretto.


2

Se provi a chiamare equals su un riferimento a un oggetto nullo, verrà generata un'eccezione del puntatore nullo.


2

Secondo le fonti non importa cosa usare per l'implementazione del metodo predefinito:

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

Ma non puoi essere sicuro della equalslezione personalizzata.


È importante, poiché equalspuò solo restituire falseo causare un NullPointerException(o qualcosa di diverso se il equalsmetodo sostituito non ha senso).
Tom

2

Se usiamo il metodo => .equals

if(obj.equals(null))  

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

Quando il tuo oggetto sarà nullo, verrà generata un'eccezione punto nullo.

quindi dovremmo usare ==

if(obj == null)

confronterà i riferimenti.


2

Object.equals è null safe, tuttavia tieni presente che se due oggetti sono null, object.equals restituirà true, quindi assicurati di controllare che gli oggetti che stai confrontando non siano null (o contengano valori null) prima di utilizzare object.equals per confronto.

String firstname = null;
String lastname = null;

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

Lo snippet di esempio sopra restituirà uguale!


Come affermato dal JavaDoc (è sempre consigliabile leggerli): Consequently, if both arguments are null, true is returned. ...:)
Thomas

1

Poiché equal è una funzione derivata dalla classe Object, questa funzione confronta gli elementi della classe. se lo usi con null restituirà una causa falsa perché il contenuto della classe non è nullo. Inoltre == confronta il riferimento a un oggetto.


Bene, il risultato può essere solo falseo NullPointerException(se equalsnon è sovrascritto da qualcosa di negativo).
Tom

1

ecco un esempio in cui str != nullma str.equals(null)quando si utilizzaorg.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




EDIT: ecco la classe 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;
    }  
}

Il problema qui è che field.equals(null)ritorna vero. Ciò interrompe il normale comportamento di Java ed è quindi fonte di confusione. Dovrebbe funzionare solo per field.equals("null"), almeno dal mio punto di vista. Non so perché gli sviluppatori della libreria pensassero che sarebbe stato utile supportare.
Tom

A proposito, la tua prima frase ha un problema di grammatica e non è chiaro cosa intendi con essa. Intendi "Ecco un esempio di dove str != nulle str.equals(null)ritorno truequando si utilizza org.json ."?
Tom

Penso che sia perché jsonObjectcontiene la chiave "campo", ecco perché fieldnon è nullo, ha un riferimento che contiene l' json.org.JSONObject$Null oggetto
dina

Sì, ma non lo tratterei Nullcome nulle lo userei "null"invece. Ma immagino che lo abbiano fatto per evitare di richiedere stringhe. Ma anche con quella libreria, field.equals(null)è ancora quasi sempre un problema: P.
Tom

0

Quindi non mi confondo mai ed evito problemi con questa soluzione:

if(str.trim().length() <=0 ) {
   // is null !
}

5
Se str è nullo, sarà un NPE
typoerrpr

Inoltre una stringa vuota (di ""lunghezza 0) è qualcosa di completamente diverso da un nullriferimento (cioè nessuna stringa).
Thomas

0

Ho riscontrato questo caso la scorsa notte.
Lo determino semplicemente che:

Non esiste il metodo equals () per null
Quindi, non puoi invocare un metodo inesistente se non hai
- >>> Questo è il motivo per cui usiamo == per controllare null


0

Il tuo codice infrange la legge di Demetra. Ecco perché è meglio rifattorizzare il design stesso. Come soluzione alternativa, puoi utilizzare Opzionale

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

sopra è controllare la gerarchia di un oggetto, quindi usa semplicemente

Optional.ofNullable(object1) 

se hai un solo oggetto da controllare

Spero che questo ti aiuti !!!!


-3

Potresti sempre farlo

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

Questo controllerà prima il riferimento all'oggetto e quindi controllerà l'oggetto stesso fornendo il riferimento non è nullo.


if (str == null || str.equals (null) || str.equals (""))
Lou Morda,

ho usato la tua risposta e ho aggiunto un segno di spunta per una stringa vuota! se non sbaglio, null e "" non sono la stessa cosa.
Lou Morda,

4
Non è completamente ridondante aggiungere un secondo controllo per null?
Justin Rowe

2
@JustinRowe Non è solo ridondante, è anche molto sbagliato. Per favore, non fare mai qualcosa del generex.equals(null) .
Tom

@ Tom, JustinRowe, per favore leggi la mia risposta sopra perché questo non è ridondante né completa la spazzatura stackoverflow.com/questions/4501061/…
dina
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.