Порівняйте два об’єкти на Java з можливими нульовими значеннями


189

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

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

Редагувати:

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

Відповіді:


173

Для цього використовується внутрішній код Java (для інших compareметодів):

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

3
Чому б просто не змінити типи String на Objects - зробивши це більш загальним? І тоді це те саме, що ви отримаєте, якщо перейдете на Java 7.
Том

3
Який клас java містить запропонований вами метод?
Володимир Левицький

30
Гей! у вас не повинно бути методу порівняння, що повертає значення true / false. Рівно - це не те саме, що порівняння. Порівняння має бути корисним для сортування. Ви повинні повернутися <0, ==0або >0вказати , який з них менше / терки , ніж інший
Coya

10
Я пропоную використовувати так, Objects.equals(Object, Object)як Марк Ротвевель зазначив у своїй відповіді (будь ласка, піднесіть це)
Нейрон

1
@Eric, що насправді не робить його менш корисним. Я впевнений, що ви не заперечуєте, що найкраща відповідь - це завжди той, що містить лише код, сумісний з усіма версіями Java, яка існувала завжди
Neuron

316

Оскільки Java 7, ви можете використовувати статичний метод java.util.Objects.equals(Object, Object)для виконання рівних перевірок на двох об'єктах, не піклуючись про те, щоб вони були null.

Якщо обидва об'єкти є, nullвін повернеться true, якщо один є, nullа інший - не повернеться false. В іншому випадку він поверне результат виклику equalsпершого об'єкта з другим як аргумент.


такий підхід відкладає перевірку типу до часу виконання програми. два наслідки: це буде повільніше під час виконання, і IDE не повідомить вас, якщо ви випадково спробуєте порівняти різні типи.
averasko

10
@averasko При використанні Object.equals(Object)немає перевірки часу компіляції. Objects.equals(Object, Object)Працює дуже так само , як нормальний equals, і повторно умовивід / перевірки по IDE, ці правила евристики, які також підтримуються для Objects.equals(Object, Object)(наприклад , IntelliJ IDEA 2016.2 має ту ж перевірку для обох нормальних рівних і один з об'єктів).
Марк Ротвевель

2
Мені подобається такий підхід. Немає необхідності включати якусь бібліотеку ApacheCommons для речей у ці дні.
Торстен Ожаперв

1
@SimonBaars Це не запуск функції на нульовому об'єкті, це статичний метод, який ви передаєте два аргументи, які можуть бути нульовими або посиланнями на об'єкт.
Марк Роттвел

8
Імхо, це повинна бути прийнята відповідь. Я не хочу винаходити колесо в кожній заявці, яку я пишу
Нейрон,

45

У цих випадках було б краще використовувати Apache Commons StringUtils # equals , він вже обробляє нульові рядки. Зразок коду:

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

Якщо ви не хочете , щоб додати бібліотеку, просто скопіюйте вихідний код цього StringUtils#equalsметоду і застосовувати його , коли вам це потрібно.


28

Для тих, хто на android, хто не може використовувати API 19's Objects.equals (str1, str2), є таке:

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

Це безпечно. Рідко доводиться використовувати більш дорогий метод string.equals (), оскільки однакові рядки на android майже завжди порівнюють істину з операндом "==" завдяки String Pool для Android , а перевірка довжини - це швидкий спосіб відфільтрувати більшість невідповідностей.

Вихідний код:

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

Оскільки версія 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

Використання 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

Порівняйте два рядки, використовуючи метод equals (-, -) та equalsIgnoreCase (-, -) класу 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


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

це те, що ти бажав?


5
Цей випадок повертається, falseякщо обидва рядки nullне є бажаним результатом.
JScoobyCed

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

    return str1.equals(str2);
}


0

Гаразд, що означає "найкраще можливе рішення"?

Якщо ви маєте на увазі найбільш читабельні, то всі можливі рішення є майже рівнозначними для досвідченого програміста Java. Але ІМО найбільше читає це

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

Іншими словами, прихойте реалізацію всередині простого методу, який (в ідеалі) можна накреслити.

(Ви також можете "вийти" в бібліотеку сторонніх утиліт ..., якщо ви вже використовуєте її у своїй кодовій базі.)


Якщо ви маєте на увазі більшість виконавців, то:

  1. найефективніше рішення залежить від платформи та контексту,
  2. одне з "контекстних" питань - відносна (динамічна) частота виникнення nullаргументів,
  3. це, мабуть, не має значення, яка версія швидша ... тому що різниця, ймовірно, занадто мала, щоб змінити загальну ефективність програми, і
  4. якщо це має значення, єдиний спосіб розібратися, який найшвидший ВАШ ПЛАТФОРМА - спробувати обидві версії та виміряти різницю.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.