Java null comprueba por qué usar == en lugar de .equals ()

125

En Java, me dicen que cuando se realiza una comprobación nula, se debe usar == en lugar de .equals (). ¿Cúales son las razones para esto?

Jim Jeffries
fuente
12
Lo más fácil es intentar verificar nulo con equals()y ver. Cuando lo intentes, será obvio al instante
Goran Jovic
Por cierto, una búsqueda en Google con palabras clave "java null check" (sin comillas) me dio como uno de los principales éxitos de este hilo , que tiene la misma información que las respuestas aquí.
Mitch Schwartz

Respuestas:

179

Son dos cosas completamente diferentes. ==compara la referencia del objeto, si la hay, contenida por una variable. .equals()comprueba si dos objetos son iguales según su contrato para lo que significa igualdad. Es completamente posible que dos instancias distintas de objetos sean "iguales" de acuerdo con su contrato. Y luego está el pequeño detalle de que, dado que equalses un método, si intentas invocarlo en una nullreferencia, obtendrás un NullPointerException.

Por ejemplo:

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
fuente
Qué quiere decir public int data?
Jé Queue
@Xepoch: No, generalmente no creo campos públicos (aunque en realidad no importa para este ejemplo de ninguna manera). ¿Por qué?
TJ Crowder
@TJ Crowder "Son dos cosas completamente diferentes ..." en general sí. Sin embargo, la implementación predeterminada de ambos es la misma, si mi comprensión es correcta. Mirando el código fuente, .equals () básicamente hace una comprobación ==. hg.openjdk.java.net/jdk7/jdk7/jdk/file/tip/src/share/classes/…
Ayush
1
@Ayush: ese es el valor predeterminado Object, sí. Sin embargo, está anulado por un gran número de clases JDK. Pero lo importante no es la implementación, sino la semántica. (Nota al margen: JDK7 está muy desactualizado.)
TJ Crowder
Bien, eso tiene sentido, solo quería aclarar.
Ayush
38

si se invoca .equals()en nullobtendráNullPointerException

Por lo tanto, siempre es aconsejable verificar la nulidad antes de invocar el método donde sea aplicable

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

Ver también

Jigar Joshi
fuente
34
Su ejemplo generalmente se escribe mejor como if ("hi".equals(str)).
ColinD
3
@ user368186: el punto no es si el método igual incluye una verificación nula. Si su referencia de objeto es nula, entonces la llamada someObject.equals(null)generará un NullPointerExceptionsin ingresar el método igual.
Dave Costa
2
@ColinD De acuerdo, solo demostrando aquí
Jigar Joshi
2
Siempre es aconsejable evitar los nulos a toda costa, por lo que no necesita cheques nulos en absoluto;).
fwielstra
2
Siempre puede usar Objects.equals(a, b)No aumentará NullPointerException, pero aún depende del método "igual" de "a" y "b"
Dominik Minc
29

Además de la respuesta aceptada ( https://stackoverflow.com/a/4501084/6276704 ):

Desde Java 1.7, si desea comparar dos objetos que pueden ser nulos, le recomiendo esta función:

Objects.equals(onePossibleNull, twoPossibleNull)

java.util.Objects

Esta clase consta de métodos de utilidad estática para operar en objetos. Estas utilidades incluyen métodos nulos seguros o nulos tolerantes para calcular el código hash de un objeto, devolver una cadena para un objeto y comparar dos objetos.

Desde: 1.7

Azul
fuente
2
Solo para hacerlo más visible para los demás (vea la respuesta de chin90 o el JavaDoc ): Objects.equals(null, null)volverá true, tenga eso en cuenta.
Thomas
20

En Java 0 o nulo son tipos simples y no objetos.

El método equals () no está diseñado para tipos simples. Los tipos simples se pueden combinar con ==.

usuario523859
fuente
44
voto a favor de la respuesta real que es más útil en lugar de la obvia "herida de respuesta NullPointerException será devuelta".
volk
4
foo.equals(null)

¿Qué pasa si foo es nulo?

Obtiene una NullPointerException.

Nick Orton
fuente
3

Si una variable Object es nula, no se puede invocar un método equals () sobre ella, por lo tanto, una comprobación de referencia de objeto de null es adecuada.

Jé Queue
fuente
2

Si intenta llamar a iguales en una referencia de objeto nulo, obtendrá una excepción de puntero nulo.

A.M
fuente
2

Según las fuentes , no importa qué usar para la implementación del método predeterminado:

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

Pero no puede estar seguro equalsen la clase personalizada.

DixonD
fuente
Es importante, ya equalsque solo puede regresar falseo causar un NullPointerException(o algo diferente si el equalsmétodo anulado no tiene sentido).
Tom
2

Si usamos el método => .equals

if(obj.equals(null))  

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

Cuando su obj sea nulo, arrojará la excepción de punto nulo.

entonces deberíamos usar ==

if(obj == null)

comparará las referencias.

AKT
fuente
2

Object.equals es nulo seguro, sin embargo, tenga en cuenta que si dos objetos son nulos, object.equals devolverá verdadero, así que asegúrese de comprobar que los objetos que está comparando no son nulos (o tienen valores nulos) antes de usar object.equals para comparación.

String firstname = null;
String lastname = null;

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

¡El fragmento de ejemplo anterior devolverá igual!

mentón90
fuente
Como lo indica el JavaDoc (siempre es aconsejable leerlos): Consequently, if both arguments are null, true is returned. ...:)
Thomas
1

Debido a que igual es una función derivada de la clase Object, esta función compara elementos de la clase. si lo usa con nulo, devolverá una causa falsa porque el contenido de la clase no es nulo. Además == compara la referencia a un objeto.

danny.lesnik
fuente
Bueno, el resultado solo puede ser falseo NullPointerException(si equalsno se reemplaza a algo malo).
Tom
1

Aquí hay un ejemplo donde str != nullpero str.equals(null)cuando se usaorg.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




EDITAR: aquí está la clase 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
fuente
El problema aquí es que field.equals(null)vuelve verdadero. Esto rompe el comportamiento habitual de Java y, por lo tanto, es confuso. Solo debería funcionar field.equals("null"), al menos en mi punto de vista. No sé por qué los desarrolladores de la biblioteca pensaron que sería bueno apoyar esto.
Tom
Por cierto, su primera oración tiene un problema de gramática y no está claro qué quiere decir con ella. ¿Quiere decir "Aquí hay un ejemplo de dónde str != nully str.equals(null)regresar trueal usar org.json "?
Tom
Creo que es porque jsonObjectcontiene la clave "campo", por eso fieldno es nulo, tiene una referencia que contiene el json.org.JSONObject$Null objeto
dina
Sí, pero no lo trataría Nullcomo nully lo usaría "null"en su lugar. Pero supongo que hicieron eso para evitar requerir cadenas. Pero incluso con ese lib, field.equals(null)sigue siendo casi siempre un problema: P.
Tom
0

Así que nunca me confundo y evito problemas con esta solución:

if(str.trim().length() <=0 ) {
   // is null !
}
Matheus Marques
fuente
55
Si str es nulo, este será un NPE
typoerrpr
Además, una cadena vacía (que ""tiene una longitud 0) es algo completamente diferente a una nullreferencia (es decir, sin cadena).
Thomas
0

Me he encontrado con este caso anoche.
Yo determino eso simplemente que:

No existe el método equals () para nulo
Entonces, no puede invocar un método inexistente si no tiene
- >>> Esa es la razón por la cual usamos == para verificar nulo

Neo_
fuente
0

Tu código infringe la ley de Demeter. Por eso es mejor refactorizar el diseño en sí. Como solución alternativa, puede usar Opcional

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

lo anterior es verificar la jerarquía de un objeto, así que simplemente use

Optional.ofNullable(object1) 

si solo tiene un objeto para verificar

Espero que esto ayude !!!!

Akitha_MJ
fuente
-3

Siempre puedes hacer

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

Esto primero verificará la referencia del objeto y luego el objeto en sí mismo, siempre que la referencia no sea nula.

Kevin Orriss
fuente
if (str == null || str.equals (null) || str.equals (""))
Lou Morda
¡Utilicé tu respuesta y agregué un cheque para una cadena vacía! si no me equivoco, nulo y "" no son lo mismo.
Lou Morda
44
¿No es completamente redundante agregar una segunda verificación para nulo?
Justin Rowe
2
@JustinRowe No solo es redundante, también está muy mal. Por favor, nunca hagas algo así x.equals(null).
Tom
@Tom, JustinRowe, por favor vea mi respuesta anterior por qué esto no es redundante ni completo stackoverflow.com/questions/4501061/…
dina