Verificação nula do Java por que usar == em vez de .equals ()

125

Em Java me disseram que, ao fazer uma verificação nula, deve-se usar == em vez de .equals (). Quais são as razões para isso?

Jim Jeffries
fonte
12
O mais fácil é tentar verificar com o null equals()e ver. Quando você tenta será imediatamente óbvia
Goran Jovic
A propósito, uma pesquisa no google com as palavras-chave "verificação nula java" (sem aspas) me deu como uma das principais ocorrências desse tópico , que tem as mesmas informações das respostas aqui.
Mitch Schwartz

Respostas:

179

São duas coisas completamente diferentes. ==compara a referência do objeto, se houver, contida por uma variável. .equals()verifica se dois objetos são iguais, de acordo com o contrato, para o que significa igualdade. É perfeitamente possível que duas instâncias de objetos distintas sejam "iguais" de acordo com o contrato. E há os pequenos detalhes de que, como equalsé um método, se você tentar invocá-lo em uma nullreferência, receberá um NullPointerException.

Por exemplo:

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
fonte
você quer dizer public int data?
Jé Queue
@ Xepoch: Não, geralmente não crio campos públicos (embora isso realmente não importe para este exemplo). Por quê?
TJ Crowder
@TJ Crowder "São duas coisas completamente diferentes .." em geral sim. No entanto, a implementação padrão de ambos é a mesma, se meu entendimento estiver correto. Observando o código fonte, .equals () basicamente faz uma verificação ==. hg.openjdk.java.net/jdk7/jdk7/jdk/file/tip/src/share/classes/…
Ayush
1
@ Ayush - Esse é o padrão Object, sim. Ele é substituído por um grande número de classes JDK. Mas o ponto não é sobre implementação, é sobre semântica. (Nota: o JDK7 está muito desatualizado.)
TJ Crowder
Certo, isso faz sentido, só queria esclarecer.
Ayush 19/06
38

Se você invocar .equals()em nullvocê obteráNullPointerException

Portanto, é sempre aconselhável verificar a nulidade antes de chamar o método, sempre que aplicável

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

Veja também

Jigar Joshi
fonte
34
Seu exemplo é geralmente melhor escrito como if ("hi".equals(str)).
colind
3
@ user368186: a questão não é se o método equals inclui uma verificação nula. Se a referência do seu objeto for nula, a chamada someObject.equals(null)aumentará a NullPointerExceptionsem nunca inserir o método equals.
Dave Costa
2
@ColinD Concorda em apenas demonstrar aqui #
444 Jigar Joshi
2
É sempre aconselhável evitar nulos a todo custo, para que você não precise de verificações nulas;).
Fwielstra
2
Você sempre pode usar Objects.equals(a, b)Ele não vai aumentar NullPointerException, mas ainda depende do método de "igual" do "a" e "b"
Dominik Minc
29

Além da resposta aceita ( https://stackoverflow.com/a/4501084/6276704 ):

Desde o Java 1.7, se você deseja comparar dois objetos que podem ser nulos, recomendo esta função:

Objects.equals(onePossibleNull, twoPossibleNull)

java.util.Objects

Esta classe consiste em métodos utilitários estáticos para operar em objetos. Esses utilitários incluem métodos nulos, seguros ou tolerantes a nulos, para calcular o código hash de um objeto, retornar uma sequência para um objeto e comparar dois objetos.

Desde: 1.7

Azul
fonte
2
Apenas para torná-lo mais visível para os outros (consulte a resposta do chin90 ou o JavaDoc ): Objects.equals(null, null)retornará true- tenha isso em mente.
Thomas
20

No Java 0 ou nulo, são tipos simples e não objetos.

O método equals () não é criado para tipos simples. Tipos simples podem ser combinados com ==.

user523859
fonte
4
upvote para a resposta real que é mais útil, em oposição ao óbvio "NullPointerException será retornado" herp derp answer.
Volk
4
foo.equals(null)

O que acontece se foo for nulo?

Você recebe uma NullPointerException.

Nick Orton
fonte
3

Se uma variável Object for nula, não será possível chamar um método equals (), portanto uma verificação de referência a objeto de null é adequada.

Jé Queue
fonte
2

Se você tentar chamar iguais em uma referência de objeto nulo, receberá uma exceção de ponteiro nulo.

SOU
fonte
2

De acordo com fontes , não importa o que usar para a implementação do método padrão:

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

Mas você não pode ter certeza equalsna classe personalizada.

DixonD
fonte
É importante, pois equalssó pode retornar falseou causar um NullPointerException(ou algo diferente se o equalsmétodo substituído não for bom).
Tom
2

Se usarmos o método => .equals

if(obj.equals(null))  

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

Quando seu objeto for nulo, ele lançará a exceção de ponto nulo.

então devemos usar ==

if(obj == null)

comparará as referências.

AKT
fonte
2

Object.equals é nulo seguro, no entanto, esteja ciente de que, se dois objetos forem nulos, object.equals retornará true, portanto, verifique se os objetos que você está comparando não são nulos (ou mantêm valores nulos) antes de usar object.equals para comparação.

String firstname = null;
String lastname = null;

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

O exemplo de snippet acima retornará igual!

chin90
fonte
Como afirma o JavaDoc (é sempre aconselhável ler as): Consequently, if both arguments are null, true is returned. ...:)
Thomas
1

Como equal é uma função derivada da classe Object, essa função compara itens da classe. se você usá-lo com nulo, ele retornará falso, porque o conteúdo da classe não é nulo. Além disso, == compara a referência a um objeto.

danny.lesnik
fonte
Bem, o resultado só pode ser falseou NullPointerException(se equalsnão for substituído por algo ruim).
26415 Tom
1

Aqui está um exemplo em que, str != nullmas str.equals(null)ao usarorg.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: aqui está a 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;
    }  
}
dina
fonte
O problema aqui é que field.equals(null)retorna verdadeiro. Isso interrompe o comportamento comum do Java e, portanto, é confuso. Deve funcionar apenas field.equals("null"), pelo menos no meu ponto de vista. Não sei por que os desenvolvedores da biblioteca pensaram que isso seria bom para dar suporte.
Tom
Aliás, sua primeira frase tem um problema de gramática e não está claro o que você quer dizer com isso. Você quer dizer "Aqui está um exemplo onde str != nulle str.equals(null)retornar trueao usar o org.json ."?
Tom
Eu acho que é porque o jsonObjectcontém a chave "campo" é por isso que fieldnão é nulo, ele tem uma referência que contém o json.org.JSONObject$Null objeto
dina
Sim, mas eu não trataria Nullcomo nulle usaria em seu "null"lugar. Mas acho que eles fizeram isso para evitar exigir Strings. Mas mesmo com essa lib, field.equals(null)ainda é quase sempre um problema: P.
Tom
0

Portanto, nunca fico confuso e evito problemas com esta solução:

if(str.trim().length() <=0 ) {
   // is null !
}
Matheus Marques
fonte
5
Se str é nulo este será um NPE
typoerrpr
Além disso, uma string vazia ( ""com comprimento 0) é algo completamente diferente de uma nullreferência (ou seja, nenhuma string).
Thomas
0

Eu encontrei este caso ontem à noite.
Eu determino que simplesmente isso:

Não existe o método equals () para null
Portanto, você não pode invocar um método inexistente se não tiver
- >>> Essa é a razão pela qual usamos == para verificar nulo

Neo_
fonte
0

Seu código infringe a lei de Deméter. É por isso que é melhor refatorar o design em si. Como solução alternativa, você pode usar o Opcional

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

acima é verificar a hierarquia de um objeto, basta usar

Optional.ofNullable(object1) 

se você tiver apenas um objeto para verificar

Espero que isto ajude !!!!

Akitha_MJ
fonte
-3

Você sempre pode fazer

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

Isso primeiro verificará a referência do objeto e depois o próprio objeto, fornecendo que a referência não seja nula.

Kevin Orriss
fonte
if (str == null || str.equals (null) || str.equals ("")))
Lou Morda
Eu usei sua resposta e adicionei um cheque para uma string vazia! se não me engano, nulo e "" não são a mesma coisa.
Lou Morda
4
Não é completamente redundante adicionar uma segunda verificação de nulo?
Justin Rowe
2
@JustinRowe Não é apenas redundante, também é muito errado. Por favor, nunca faça algo parecido x.equals(null).
26415 Tom
@ Tom, JustinRowe consulte minha resposta acima por que isso não é redundante nem completa lixo stackoverflow.com/questions/4501061/...
dina