Compare dois objetos em Java com possíveis valores nulos

Respostas:

173

É isso que o código interno Java usa (em outros comparemétodos):

public static boolean compare(String str1, String str2) {
    return (str1 == null ? str2 == null : str1.equals(str2));
}
Eric
fonte
3
Por que não apenas alterar os tipos de String para Objetos - tornando-os mais genéricos? E então é o mesmo que o que você vai ficar se você se mover para Java 7.
Tom
3
Qual classe java contém o método que você forneceu?
Volodymyr Levytskyi
30
Ei! você não deve ter um método de comparação retornando verdadeiro / falso. Igual a não é o mesmo que comparar. A comparação deve ser útil para classificação. Você deve retornar <0, ==0ou >0para indicar qual é inferior / ralador do que o outro
coya
10
Eu sugiro usar Objects.equals(Object, Object)como Mark Rotteveel assinalou em sua resposta (por favor upvote-lo)
Neuron
1
@ Eric, que realmente não a torna menos uma boa resposta. Tenho certeza que você não discutiria a melhor resposta é sempre a que contém somente o código que é compatível com todas as versões java que sempre existiu
Neuron
318

Desde o Java 7, você pode usar o método estático java.util.Objects.equals(Object, Object)para executar verificações iguais em dois objetos sem se preocupar com eles null.

Se ambos os objetos estiverem, nullele retornará true; se um estiver nulle outro não, retornará false. Caso contrário, ele retornará o resultado da chamada equalsno primeiro objeto com o segundo como argumento.

Mark Rotteveel
fonte
essa abordagem adia a verificação de tipo até o tempo de execução do programa. duas conseqüências: será mais lento no tempo de execução e o IDE não informará se você acidentalmente tentar comparar tipos diferentes.
averasko
10
@averasko Quando você usa, Object.equals(Object)não há verificação do tipo de tempo de compilação. O Objects.equals(Object, Object)funciona muito bem o mesmo que um normal, equalse re inferência / cheques por IDE, essas regras são heurísticas que também são suportados para Objects.equals(Object, Object)(por exemplo, IntelliJ IDEA 2.016,2 tem o mesmo cheque para ambos os iguais normais e o de objetos).
Mark Rotteveel
2
Eu gosto dessa abordagem. Não há necessidade de incluir alguma biblioteca ApacheCommons para as coisas atualmente.
Torsten Ojaperv
1
@SimonBaars Isso não está executando uma função em um objeto nulo, é um método estático que você transmite dois argumentos, que podem ser nulos ou uma referência a um objeto.
Mark Rotteveel
8
imho esta deve ser a resposta aceita. Eu não quero reinventar a roda em cada gravação única aplicação I
Neuron
45

Para esses casos, seria melhor usar o Apache Commons StringUtils # igual , pois ele já manipula cadeias nulas. Exemplo de código:

public boolean compare(String s1, String s2) {
    return StringUtils.equals(s1, s2);
}

Se você não deseja adicionar a biblioteca, basta copiar o código-fonte do StringUtils#equalsmétodo e aplicá-lo quando necessário.

Luiggi Mendoza
fonte
29

Para aqueles no Android, que não podem usar o Object.equals da API 19 (str1, str2), existe o seguinte:

android.text.TextUtils.equals(str1, str2);

É nulo seguro. Raramente é necessário usar o método string.equals () mais caro, porque seqüências de caracteres idênticas no android quase sempre comparam true com o operando "==" graças ao Pool de cordas do Android , e as verificações de comprimento são uma maneira rápida de filtrar a maioria das incompatibilidades.

Código fonte:

/**
 * Returns true if a and b are equal, including if they are both null.
 * <p><i>Note: In platform versions 1.1 and earlier, this method only worked  well if
 * both the arguments were instances of String.</i></p>
 * @param a first CharSequence to check
 * @param b second CharSequence to check
 * @return true if a and b are equal
 */
public static boolean equals(CharSequence a, CharSequence b) {
    if (a == b) return true;
    int length;
    if (a != null && b != null && (length = a.length()) == b.length()) {
        if (a instanceof String && b instanceof String) {
            return a.equals(b);
        } else {
            for (int i = 0; i < length; i++) {
                if (a.charAt(i) != b.charAt(i)) return false;
            }
            return true;
        }
    }
    return false;
}
NameSpace
fonte
7

Desde a versão 3.5, o Apache Commons StringUtils possui os seguintes métodos:

static int  compare(String str1, String str2)
static int  compare(String str1, String str2, boolean nullIsLess)
static int  compareIgnoreCase(String str1, String str2)
static int  compareIgnoreCase(String str1, String str2, boolean nullIsLess)

Eles fornecem comparação de nula segura e segura.

phn
fonte
6

Usando o Java 8:

private static Comparator<String> nullSafeStringComparator = Comparator
        .nullsFirst(String::compareToIgnoreCase); 

private static Comparator<Metadata> metadataComparator = Comparator
        .comparing(Metadata::getName, nullSafeStringComparator)
        .thenComparing(Metadata::getValue, nullSafeStringComparator);

public int compareTo(Metadata that) {
    return metadataComparator.compare(this, that);
}
TanvirChowdhury
fonte
4

Compare duas cadeias usando o método equals (-, -) e equalsIgnoreCase (-, -) da classe Apache Commons StringUtils.

StringUtils.equals (-, -) :

StringUtils.equals(null, null)   = true
StringUtils.equals(null, "abc")  = false
StringUtils.equals("abc", null)  = false
StringUtils.equals("abc", "abc") = true
StringUtils.equals("abc", "ABC") = false

StringUtils.equalsIgnoreCase (-, -) :

StringUtils.equalsIgnoreCase(null, null)   = true
StringUtils.equalsIgnoreCase(null, "abc")  = false
StringUtils.equalsIgnoreCase("xyz", null)  = false
StringUtils.equalsIgnoreCase("xyz", "xyz") = true
StringUtils.equalsIgnoreCase("xyz", "XYZ") = true
Prashant Sahoo
fonte
3

Você pode usar da java.util.Objectsseguinte maneira.

public static boolean compare(String str1, String str2) {
    return Objects.equals(str1, str2);
}
Jobi Subramunian
fonte
2
boolean compare(String str1, String str2) {
    if(str1==null || str2==null) {
        //return false; if you assume null not equal to null
        return str1==str2;
    }
    return str1.equals(str2);
}

é isso que você deseja?

didxga
fonte
5
Este caso retornará falsese as duas Strings forem nullque podem não ser o resultado desejado.
JScoobyCed
1
boolean compare(String str1, String str2) {
    if (str1 == null || str2 == null)
        return str1 == str2;

    return str1.equals(str2);
}
Kierrow
fonte
1
boolean compare(String str1, String str2) {
  return (str1==null || str2==null) ? str1 == str2 : str1.equals(str2);
}
Sumit Singh
fonte
0

OK, então o que significa "melhor solução possível"?

Se você quer dizer mais legível, todas as soluções possíveis são praticamente equivalentes para um programador Java experiente. Mas o IMO, o mais legível é esse

 public boolean compareStringsOrNulls(String str1, String str2) {
     // Implement it how you like
 }

Em outras palavras, oculte a implementação dentro de um método simples que (idealmente) possa ser incorporado.

(Você também pode "terceirizar" uma biblioteca de utilitários de terceiros ... se você já a usa na sua base de código.)


Se você quer dizer o melhor desempenho, então:

  1. a solução com melhor desempenho depende da plataforma e do contexto,
  2. um dos problemas de "contexto" é a frequência relativa (dinâmica) da ocorrência de nullargumentos,
  3. ele provavelmente não importa qual versão é mais rápido ... porque a diferença é provavelmente muito pequena para fazer a diferença para o desempenho geral do aplicativo e
  4. se isso importa, a única maneira de descobrir qual é o mais rápido EM SUA PLATAFORMA é tentar as duas versões e medir a diferença.
Stephen C
fonte