Java null vérifie pourquoi utiliser == au lieu de .equals ()


125

En Java, on me dit que lors d'un contrôle nul, il faut utiliser == au lieu de .equals (). Quelles en sont les raisons?


12
La chose la plus simple est d'essayer la vérification de null avec equals()et de voir. Lorsque vous essayez, il sera instantanément évident
Goran Jovic

À propos, une recherche Google avec les mots clés "java null check" (sans guillemets) m'a donné comme l'un des meilleurs résultats de ce fil , qui a les mêmes informations que les réponses ici.
Mitch Schwartz

Réponses:


179

Ce sont deux choses complètement différentes. ==compare la référence d'objet, le cas échéant, contenue dans une variable. .equals()vérifie si deux objets sont égaux selon leur contrat pour ce que signifie l'égalité. Il est tout à fait possible que deux instances d'objets distinctes soient «égales» selon leur contrat. Et puis il y a le détail mineur qui equalsest une méthode, si vous essayez de l'invoquer sur une nullréférence, vous obtiendrez un NullPointerException.

Par exemple:

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

voulez-vous dire public int data?
Jé Queue

@Xepoch: Non, je ne crée généralement pas de champs publics (même si cela n'a pas vraiment d'importance pour cet exemple de toute façon). Pourquoi?
TJ Crowder du

@TJ Crowder "Ce sont deux choses complètement différentes .." en général oui. Cependant, l'implémentation par défaut des deux est la même, si ma compréhension est correcte. En regardant le code source, .equals () effectue essentiellement une vérification ==. hg.openjdk.java.net/jdk7/jdk7/jdk/file/tip/src/share/classes/…
Ayush

1
@Ayush - C'est la valeur par défaut Object, oui. Il est cependant remplacé par un grand nombre de classes JDK. Mais ce n'est pas une question d'implémentation, mais de sémantique. (Note latérale: JDK7 est très obsolète.)
TJ Crowder

Bon, cela a du sens, je voulais juste clarifier.
Ayush

38

si vous invoquez .equals(), nullvous obtiendrezNullPointerException

Il est donc toujours conseillé de vérifier la nullité avant d'appeler la méthode où qu'elle s'applique

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

Regarde aussi


34
Votre exemple est généralement mieux rédigé sous la forme if ("hi".equals(str)).
ColinD

3
@ user368186: le point n'est pas de savoir si la méthode equals inclut une vérification nulle. Si votre référence d'objet est nulle, l'appel someObject.equals(null)lèvera a NullPointerExceptionsans jamais entrer la méthode equals.
Dave Costa

2
@ColinD D'accord, il suffit de démontrer ici
Jigar Joshi

2
Il est toujours conseillé d'éviter à tout prix les valeurs nulles, vous n'avez donc pas du tout besoin de vérifications nulles;).
fwielstra

2
Vous pouvez toujours utiliser Objects.equals(a, b)Cela ne lèvera pas NullPointerException, mais cela dépend toujours de la méthode "égale" du "a" et du "b"
Dominik Minc

29

En plus de la réponse acceptée ( https://stackoverflow.com/a/4501084/6276704 ):

Depuis Java 1.7, si vous souhaitez comparer deux objets qui peuvent être nuls, je recommande cette fonction:

Objects.equals(onePossibleNull, twoPossibleNull)

java.util.Objects

Cette classe se compose de méthodes utilitaires statiques permettant d'opérer sur des objets. Ces utilitaires incluent des méthodes de sécurité nulle ou tolérantes à zéro pour calculer le code de hachage d'un objet, renvoyer une chaîne pour un objet et comparer deux objets.

Depuis: 1.7


2
Juste pour le rendre plus visible pour les autres (voir la réponse de chin90 ou le JavaDoc ): Objects.equals(null, null)reviendra true- gardez cela à l'esprit.
Thomas

20

En Java, 0 ou null sont des types simples et non des objets.

La méthode equals () n'est pas conçue pour les types simples. Les types simples peuvent être mis en correspondance avec ==.


4
upvote pour la réponse réelle qui est la plus utile par opposition à la réponse évidente "NullPointerException sera retournée" herp derp.
volk

4
foo.equals(null)

Que se passe-t-il si foo est nul?

Vous obtenez une NullPointerException.


3

Si une variable Object est nulle, on ne peut pas appeler une méthode equals () dessus, donc une vérification de référence d'objet de null est appropriée.


2

Si vous essayez d'appeler equals sur une référence d'objet nulle, vous obtiendrez une exception de pointeur nul levée.


2

Selon les sources , peu importe ce qu'il faut utiliser pour l'implémentation de la méthode par défaut:

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

Mais vous ne pouvez pas en être sûr equalsdans la classe personnalisée.


C'est important, car equalsne peut retourner falseou provoquer un NullPointerException(ou quelque chose de différent si la equalsméthode surchargée est absurde).
Tom du

2

Si nous utilisons la méthode => .equals

if(obj.equals(null))  

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

Lorsque votre obj sera nul, il lèvera une exception de point nul.

nous devrions donc utiliser ==

if(obj == null)

il comparera les références.


2

Object.equals est null safe, mais sachez que si deux objets sont null, object.equals retournera true donc assurez-vous de vérifier que les objets que vous comparez ne sont pas null (ou contiennent des valeurs nulles) avant d'utiliser object.equals pour Comparaison.

String firstname = null;
String lastname = null;

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

L'exemple d'extrait ci-dessus renverra égal!


Comme indiqué par le JavaDoc (il est toujours sage de les lire): Consequently, if both arguments are null, true is returned. ...:)
Thomas

1

Étant donné qu'égal est une fonction dérivée de la classe Object, cette fonction compare les éléments de la classe. si vous l'utilisez avec null, il retournera false car le contenu de la classe n'est pas nul. De plus == compare la référence à un objet.


Eh bien, le résultat ne peut être que falseou NullPointerException(s'il equalsn'est pas remplacé par quelque chose de mauvais).
Tom

1

voici un exemple où str != nullmais str.equals(null)lors de l'utilisationorg.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: voici 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;
    }  
}

Le problème ici est que cela field.equals(null)renvoie vrai. Cela rompt le comportement habituel de Java et prête donc à confusion. Cela ne devrait fonctionner que pour field.equals("null"), du moins à mon avis. Je ne sais pas pourquoi les développeurs de la bibliothèque ont pensé que ce serait bon à supporter.
Tom

Btw, votre première phrase a un problème de grammaire et ce que vous voulez dire n'est pas clair. Voulez-vous dire "Voici un exemple où str != nullet de str.equals(null)retour truelors de l'utilisation de org.json ."?
Tom

Je pense que c'est parce que le jsonObjectcontient la clé "field", c'est pourquoi il fieldn'est pas nul, il a une référence qui contient l' json.org.JSONObject$Null objet
dina

Oui, mais je ne traiterais pas Nullcomme nullet utiliserais à la "null"place. Mais je suppose qu'ils ont fait cela pour éviter d'avoir besoin de cordes. Mais même avec cette bibliothèque, field.equals(null)c'est toujours presque toujours un problème: P.
Tom

0

Donc, je ne me trompe jamais et évite les problèmes avec cette solution:

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

5
Si str est nul, ce sera un NPE
typoerrpr

De plus, une chaîne vide (de ""longueur 0) est quelque chose de complètement différent d'une nullréférence (c'est-à-dire pas de chaîne).
Thomas

0

J'ai rencontré ce cas hier soir.
Je détermine simplement que:

N'existe pas la méthode equals () pour null
Donc, vous ne pouvez pas invoquer une méthode inexistante si vous n'avez pas
- >>> C'est la raison pour laquelle nous utilisons == pour vérifier null


0

Votre code enfreint la loi de Demeter. C'est pourquoi il est préférable de refactoriser le design lui-même. Pour contourner ce problème, vous pouvez utiliser facultatif

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

ci-dessus est de vérifier la hiérarchie d'un objet donc utilisez simplement

Optional.ofNullable(object1) 

si vous n'avez qu'un seul objet à vérifier

J'espère que cela t'aides !!!!


-3

Tu pourrais toujours faire

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

Cela vérifiera d'abord la référence de l'objet, puis vérifiera l'objet lui-même en fournissant que la référence n'est pas nulle.


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

J'ai utilisé votre réponse et ajouté un chèque pour une chaîne vide! si je ne me trompe pas, nul et "" ne sont pas la même chose.
Lou Morda

4
N'est-il pas complètement redondant d'ajouter une deuxième vérification de null?
Justin Rowe

2
@JustinRowe Ce n'est pas seulement redondant, c'est aussi très faux. S'il vous plaît, ne faites jamais quelque chose comme x.equals(null).
Tom du

@Tom, JustinRowe s'il vous plaît voir ma réponse ci-dessus pourquoi ce n'est pas redondant ni complet garbage stackoverflow.com/questions/4501061/…
dina
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.