Confronta due oggetti in Java con possibili valori null


189

Voglio confrontare due stringhe per l'uguaglianza in Java, quando uno o entrambi potrebbero essere null, quindi non posso semplicemente chiamare .equals(). Qual è il modo migliore?

boolean compare(String str1, String str2) {
    ...
}

Modificare:

return ((str1 == str2) || (str1 != null && str1.equals(str2)));

Risposte:


173

Questo è ciò che utilizza il codice interno Java (su altri comparemetodi):

public static boolean compare(String str1, String str2) {
    return (str1 == null ? str2 == null : str1.equals(str2));
}

3
Perché non cambiare semplicemente i tipi di stringa in Oggetti, rendendolo più generico? E poi è lo stesso di quello che otterrai se ti sposti a Java 7.
Tom

3
Quale classe java contiene il metodo che hai fornito?
Volodymyr Levytskyi,

30
Hey! non dovresti avere un metodo di confronto che restituisca vero / falso. Equals non è lo stesso del confronto. Il confronto dovrebbe essere utile per l'ordinamento. Dovresti tornare <0, ==0o >0per indicare quale è più basso / più
grattoso

10
suggerisco di usare Objects.equals(Object, Object)come Mark Rotteveel ha sottolineato nella sua risposta (per favore, votalo)
Neuron

1
@Eric che non lo rende davvero una buona risposta. Sono sicuro che non sosterresti che la risposta migliore è sempre quella contenente solo codice compatibile con ogni versione java che sia sempre esistita
Neuron

318

Da Java 7 è possibile utilizzare il metodo statico java.util.Objects.equals(Object, Object)per eseguire controlli uguali su due oggetti senza preoccuparsene null.

Se entrambi gli oggetti sono null, tornerà true, se uno è nulle un altro no, tornerà false. Altrimenti restituirà il risultato della chiamata equalsal primo oggetto con il secondo come argomento.


questo approccio ignora il controllo del tipo fino al runtime del programma. due conseguenze: sarà più lento in fase di esecuzione e IDE non ti farà sapere se per caso cerchi di confrontare diversi tipi.
averasko,

10
@averasko Quando si utilizza Object.equals(Object)non esiste un controllo del tipo di tempo di compilazione. Il Objects.equals(Object, Object)funziona molto simile come un normale equals, e ri inferenza / controlli da IDE, quelle regole euristiche sono anch'esse supportate per Objects.equals(Object, Object)(es IntelliJ IDEA 2016,2 ha lo stesso controllo per entrambe le eguali normali e quello da oggetti).
Mark Rotteveel, il

2
Mi piace questo approccio. Al giorno d'oggi non è necessario includere alcune librerie di ApacheCommons.
Torsten Ojaperv,

1
@SimonBaars Questo non esegue una funzione su un oggetto null, questo è un metodo statico che passa due argomenti, che può essere null, o un riferimento a un oggetto.
Mark Rotteveel,

8
imho questa dovrebbe essere la risposta accettata. Non voglio reinventare la ruota in ogni singola applicazione che scrivo
Neuron

45

In questi casi sarebbe meglio usare Apache Commons StringUtils # uguale a , gestisce già stringhe null. Esempio di codice:

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

Se non si desidera aggiungere la libreria, è sufficiente copiare il codice sorgente del StringUtils#equalsmetodo e applicarlo quando è necessario.


29

Per quelli su Android, che non possono usare Objects.equals (str1, str2) dell'API 19, c'è questo:

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

È null sicuro. Raramente deve usare il metodo string.equals () più costoso perché stringhe identiche su Android quasi sempre si confrontano con l'operando "==" grazie al pool di stringhe di Android , e i controlli di lunghezza sono un modo veloce per filtrare la maggior parte delle mancate corrispondenze.

Codice sorgente:

/**
 * 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;
}

7

Dalla versione 3.5 di Apache Commons StringUtils ha i seguenti metodi:

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)

Questi forniscono un confronto di stringhe sicuro.


6

Utilizzando 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);
}

4

Confronta due stringhe usando il metodo equals (-, -) e equalsIgnoreCase (-, -) della classe StringUtils di Apache Commons.

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

3

Puoi usare java.util.Objectscome segue.

public static boolean compare(String str1, String str2) {
    return Objects.equals(str1, str2);
}

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);
}

è questo quello che volevi?


5
Questo caso ritorna falsese entrambe le stringhe nullpotrebbero non essere il risultato desiderato.
JScoobyCed

1
boolean compare(String str1, String str2) {
    if (str1 == null || str2 == null)
        return str1 == str2;

    return str1.equals(str2);
}

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

0

OK, quindi cosa significa "migliore soluzione possibile"?

Se vuoi dire più leggibile, allora tutte le possibili soluzioni sono praticamente equivalenti per un programmatore Java esperto. Ma l'IMO più leggibile è questo

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

In altre parole, nascondere l'implementazione all'interno di un metodo semplice che (idealmente) può essere integrato.

(Potresti anche "esternalizzare" a una libreria di utilità di terze parti ... se la usi già nella tua base di codice.)


Se vuoi dire il più performante, allora:

  1. la soluzione più performante dipende dalla piattaforma e dal contesto,
  2. uno dei problemi del "contesto" è la frequenza relativa (dinamica) del verificarsi di nullargomenti,
  3. che probabilmente non importa quale versione è più veloce ... perché la differenza è probabilmente troppo piccolo per fare la differenza per le prestazioni complessive dell'applicazione e
  4. se è importante, l'unico modo per capire quale sia il più veloce SULLA PIATTAFORMA è provare entrambe le versioni e misurare la differenza.
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.