Сравните два объекта в Java с возможными нулевыми значениями

Я хочу сравнить две строки для равенства в Java, когда один или оба могут быть null, поэтому я не могу просто вызвать .equals(). Каков наилучший способ?

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

Изменить:

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

Ответы

Ответ 1

Это то, что использует внутренний код Java (в других методах compare):

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

Ответ 2

Начиная с Java 7 вы можете использовать статический метод java.util.Objects.equals(Object, Object) для выполнения проверки на равенство двух объектов, не заботясь о том, чтобы они были null.

Если оба объекта равны null он вернет true, если один будет null а другой нет, он вернет false. В противном случае он вернет результат вызова equals для первого объекта со вторым в качестве аргумента.

Ответ 3

Для этих случаев было бы лучше использовать Apache Commons StringUtils # equals, он уже обрабатывает нулевые строки. Пример кода:

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

Если вы не хотите добавлять библиотеку, просто скопируйте исходный код метода StringUtils#equals и примените его, когда вам это нужно.

Ответ 4

Для тех, кто на android, которые не могут использовать API 19 Objects.equals(str1, str2), есть следующее:

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

Это безопасно. Редко приходится использовать более дорогой метод string.equals(), потому что идентичные строки в android почти всегда сравниваются с операндом "==" благодаря Android String Pooling и длинные проверки - это быстрый способ отфильтровать большинство несоответствий.

Исходный код:

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

Ответ 5

Поскольку версия 3.5 Apache Commons StringUtils имеет следующие методы:

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)

Они обеспечивают нулевое безопасное сравнение строк.

Ответ 6

Сравните две строки, используя метод equals (-, -) и equalsIgnoreCase (-, -) класса StringUtils 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

Ответ 7

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

это то, что вы хотели?

Ответ 8

Используя 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);
}

Ответ 9

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

    return str1.equals(str2);
}

Ответ 10

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

Ответ 11

Вы можете использовать java.util.Objects следующим образом.

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

Ответ 12

ОК, так что означает "наилучшее возможное решение"?

Если вы имеете в виду большинство читаемых, то все возможные решения в значительной степени эквивалентны опытному программисту Java. Но IMO наиболее читаемым является этот

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

Другими словами, скройте реализацию внутри простого метода, который (в идеале) может быть встроен.

(Вы также можете использовать "out-source" для сторонней библиотеки утилиты... если вы уже используете его в своей кодовой базе.)


Если вы имеете в виду большинство исполнителей, то:

  • наиболее эффективное решение зависит от платформы и контекста,
  • одной из проблем "контекста" является относительная (динамическая) частота появления аргументов null,
  • Вероятно, неважно, какая версия быстрее... потому что разница, вероятно, слишком мала, чтобы иметь значение для общей производительности приложения и
  • Если это имеет значение, единственный способ выяснить, который быстрее всего работает на вашей PLATFORM, - попробовать обе версии и измерить разницу.