Какое равенство проверяет метод Apache Commons ObjectUtils? - PullRequest
16 голосов
/ 25 января 2010

Я всегда понимал, что в Java существует два типа равенства,

  • значение равенства : использует метод .equals() для проверки того, что два объекта реализуют отношение эквивалентности для ненулевых ссылок на объекты.
  • ссылочное равенство : использует оператор == для проверки того, что два примитивных типа или места в памяти равны.

На следующих страницах эти основы языка описаны более подробно.

То, что ни одна из этих ссылок явно не указывает, - это то, что должно произойти, если две null ссылки на объекты сравниваются на равенство значений. Неявное предположение состоит в том, что NullPointerException должно быть выброшено, но это не то, что делается методом ObjectUtils.equals () , который можно рассматривать как метод полезной практики .

Что меня беспокоит, так это то, что Apache Commons , кажется, эффективно ввел третью меру равенства в Java через черный ход, и что и без того запутанное положение дел могло бы быть значительно более сложным. Я называю это третьей мерой равенства, потому что она пытается проверить на равенство значений, а когда это не удается, возвращается к проверке на равенство ссылок. Тест на равенство Apache Commons имеет много общего с равенством значений и ссылочным равенством, но также заметно отличается.

Правильно ли я беспокоюсь и хочу избегать использования ObjectUtils.equals(), где это возможно?

Есть ли аргумент для утверждения, что ObjectUtils.equals() обеспечивает полезное объединение двух других мер равенства?

Выбранный ответ

Похоже, что по этому вопросу нет единого мнения, но я решил пометить Божо как правильное, потому что он лучше всего обратил мое внимание на то, что я сейчас вижу, как наибольшую проблему с проверками на равенство при нулевой безопасности. Мы все должны писать fail-fast код, который устраняет основную причину, по которой два нулевых объекта сравниваются на равенство значений вместо того, чтобы пытаться скрыть проблему.

Ответы [ 3 ]

10 голосов
/ 25 января 2010

Вот код ObjectUtils.equals(..):

public static boolean equals(Object object1, Object object2) {
     if (object1 == object2) {
       return true;
     }
     if ((object1 == null) || (object2 == null)) {
       return false;
    }
    return object1.equals(object2);
}

Документы ObjecUtils четко указывают, что переданные объекты могут быть нулевыми.

Теперь о том, следует ли возвращать true, если сравнить два null с. На мой взгляд - нет, потому что:

  • когда вы сравниваете два объекта, вы, вероятно, будете что-то делать с ними позже. Это приведет к NullPointerException
  • Передача двух null с для сравнения означает, что они получили откуда-то вместо "реальных" объектов, возможно, из-за какой-то проблемы. В этом случае сравнивать их по отдельности неверно - поток программы должен был быть остановлен до этого.
  • В пользовательской библиотеке, которую мы здесь используем, у нас есть метод с именем equalOrBothNull(), который отличается от метода equals в этой утилите сравнением нуля.
5 голосов
/ 25 января 2010

Прав ли я быть обеспокоенным и хотеть чтобы избежать использования ObjectUtils.equals () где угодно возможно

Нет. То, что вы должны считать равным, зависит от ваших требований. И желание считать два нуля равными и любое ненулевое неравное нулю без необходимости иметь дело с NullPointerExceptions - это очень и очень распространенное требование (например, когда вы хотите инициировать события изменения значения из установщика).

На самом деле, именно так equals() в целом должно работать , и, как правило, половина этой команды реализована (документ API Object.equals() сообщает "для любого ненулевого ссылочного значения x , x.equals(null) должен возвращать false. ") - то, что он не работает наоборот, в основном из-за технических ограничений (язык был разработан без многократной отправки , чтобы быть более простым).

1 голос
/ 25 января 2010

Если вас это беспокоит, вы можете либо: 1) не использовать этот метод 2) написать свой собственный, чтобы обернуть его

public class MyObjectUtils {
    public static boolean equals(Object obj1, Object obj2) {
        return obj1 != null && obj2 != null && ObjectUtils.equals(obj1, obj2);
    }
}

Мне кажется странным допускать, чтобы значение null было равно нулю, но это не кажется большой проблемой. По большей части я бы не ожидал, что мое приложение попадет даже в пути кода, которые включают в себя тесты на равенство, если один или несколько объектов равны нулю.

...