Подтвердить что ты не робот

Какое равенство делает Apache Commons ObjectUtils равным методу тестирования?

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

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

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

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

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

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

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

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

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

4b9b3361

Ответ 1

Здесь код 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 docs четко заявляют, что переданные объекты могут быть пустыми.

Теперь о том, нужно ли возвращать true, если вы сравниваете два null s. По-моему - нет, потому что:

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

Ответ 2

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

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

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

Ответ 3

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

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

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