Vergleichen Sie zwei Objekte in Java mit möglichen Nullwerten

189

Ich möchte zwei Zeichenfolgen für die Gleichheit in Java vergleichen, wenn eine oder beide vorhanden sein könnten null, daher kann ich nicht einfach aufrufen .equals(). Was ist der beste Weg?

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

Bearbeiten:

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

Antworten:

173

Dies ist, was Java-interner Code verwendet (bei anderen compareMethoden):

public static boolean compare(String str1, String str2) {
    return (str1 == null ? str2 == null : str1.equals(str2));
}
Eric
quelle
3
Warum ändern Sie nicht einfach die Zeichenfolgentypen in Objekte, um sie allgemeiner zu gestalten? Und dann ist es dasselbe wie das, was Sie erhalten, wenn Sie zu Java 7 wechseln.
Tom
3
Welche Java-Klasse enthält die von Ihnen bereitgestellte Methode?
Volodymyr Levytskyi
30
Hallo! Sie sollten keine Vergleichsmethode haben, die true / false zurückgibt. Gleich ist nicht dasselbe wie vergleichen. Vergleichen sollte zum Sortieren nützlich sein. Sie sollten zurückkehren <0, ==0oder >0um anzuzeigen , welche ein niedriger / Reibe als die andere
coya
10
Ich schlage vor, Objects.equals(Object, Object)wie Mark Rotteveel in seiner Antwort darauf hingewiesen hat (bitte positiv bewerten)
Neuron
1
@ Eric, das macht es nicht weniger zu einer guten Antwort. Ich bin sicher, Sie würden nicht argumentieren, dass die beste Antwort immer die ist, die nur Code enthält, der mit jeder Java-Version kompatibel ist, die es immer gegeben hat
Neuron
315

Seit Java 7 können Sie die statische Methode verwenden java.util.Objects.equals(Object, Object), um zwei Objekte gleich zu prüfen, ohne sich um sie zu kümmern null.

Wenn beide Objekte vorhanden sind null, wird es zurückgegeben true, wenn eines vorhanden ist nullund eines nicht, wird es zurückgegeben false. Andernfalls wird das Ergebnis des Aufrufs equalsdes ersten Objekts mit dem zweiten als Argument zurückgegeben.

Mark Rotteveel
quelle
Dieser Ansatz verschiebt die Typprüfung bis zur Laufzeit des Programms. Zwei Konsequenzen: Es wird zur Laufzeit langsamer und IDE lässt Sie nicht wissen, wenn Sie versehentlich versuchen, verschiedene Typen zu vergleichen.
Averasko
10
@averasko Bei Verwendung Object.equals(Object)erfolgt keine Typprüfung zur Kompilierungszeit. Das Objects.equals(Object, Object)funktioniert sehr ähnlich wie ein normales equalsund Rückschluss / Überprüfung durch IDE, diese Regeln sind Heuristiken, die ebenfalls unterstützt werden Objects.equals(Object, Object)(z. B. hat IntelliJ IDEA 2016.2 die gleiche Prüfung sowohl für die normale Gleichheit als auch für die von Objekten).
Mark Rotteveel
2
Ich mag diesen Ansatz. Heutzutage ist es nicht mehr erforderlich, eine ApacheCommons-Bibliothek einzuschließen.
Torsten Ojaperv
1
@SimonBaars Hiermit wird keine Funktion für ein Nullobjekt ausgeführt. Dies ist eine statische Methode, bei der Sie zwei Argumente übergeben, die null sein können, oder einen Verweis auf ein Objekt.
Mark Rotteveel
8
Imho sollte dies die akzeptierte Antwort sein. Ich möchte das Rad nicht in jeder einzelnen Anwendung, die ich schreibe, neu erfinden
Neuron
45

In diesen Fällen ist es besser, Apache Commons StringUtils # equals zu verwenden . Es werden bereits Nullzeichenfolgen verarbeitet. Codebeispiel:

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

Wenn Sie die Bibliothek nicht hinzufügen möchten, kopieren Sie einfach den Quellcode der StringUtils#equalsMethode und wenden Sie ihn bei Bedarf an.

Luiggi Mendoza
quelle
28

Für diejenigen auf Android, die Objects.equals (str1, str2) von API 19 nicht verwenden können, gibt es Folgendes:

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

Es ist null sicher. Es muss selten die teurere string.equals () -Methode verwendet werden, da identische Strings auf Android dank Android's String Pooling fast immer mit dem Operanden "==" verglichen werden und Längenprüfungen eine schnelle Möglichkeit sind, die meisten Fehlanpassungen herauszufiltern.

Quellcode:

/**
 * 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
quelle
7

Seit Version 3.5 hat Apache Commons StringUtils die folgenden Methoden:

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)

Diese bieten einen null-sicheren String-Vergleich.

phn
quelle
6

Verwenden von 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
quelle
4

Vergleichen Sie zwei Zeichenfolgen mit den Methoden equals (-, -) und equalsIgnoreCase (-, -) der Apache Commons StringUtils-Klasse.

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
quelle
3

Sie können java.util.ObjectsFolgendes verwenden.

public static boolean compare(String str1, String str2) {
    return Objects.equals(str1, str2);
}
Jobi Subramunian
quelle
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);
}

ist es das, was du gewünscht hast?

didxga
quelle
5
Dieser Fall wird zurückgegeben, falsewenn beide Zeichenfolgen nulldas gewünschte Ergebnis sind.
JScoobyCed
1
boolean compare(String str1, String str2) {
    if (str1 == null || str2 == null)
        return str1 == str2;

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

OK, was bedeutet "bestmögliche Lösung"?

Wenn Sie am besten lesbar meinen, dann sind alle möglichen Lösungen für einen erfahrenen Java-Programmierer ziemlich gleichwertig. Aber IMO ist dies am besten lesbar

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

Mit anderen Worten, verstecken Sie die Implementierung in einer einfachen Methode, die (idealerweise) eingebunden werden kann.

(Sie können auch eine Dienstprogrammbibliothek eines Drittanbieters "auslagern" ... wenn Sie sie bereits in Ihrer Codebasis verwenden.)


Wenn Sie am performantesten meinen, dann:

  1. Die leistungsstärkste Lösung hängt von der Plattform und dem Kontext ab.
  2. Eines der "Kontext" -Probleme ist die relative (dynamische) Häufigkeit des Auftretens von nullArgumenten.
  3. Es spielt wahrscheinlich keine Rolle, welche Version schneller ist ... da der Unterschied wahrscheinlich zu gering ist, um die Gesamtleistung der Anwendung zu beeinflussen, und
  4. Wenn es wichtig ist, können Sie nur herausfinden, welche Version auf Ihrer Plattform am schnellsten ist, indem Sie beide Versionen ausprobieren und den Unterschied messen.
Stephen C.
quelle