Какое равенство делает Apache Commons ObjectUtils равным методу тестирования?
Я всегда понимал, что существуют два типа равенства в Java,
- Значение: использует метод
.equals()
для проверки того, что два объекта реализуют отношение эквивалентности для ненулевых ссылок на объекты.
- ссылочное равенство: использует оператор
==
для проверки того, что два примитивных типа или ячейки памяти равны.
Следующие страницы более подробно описывают эти языковые основы.
То, что явно не указано ни одной из этих ссылок, - это то, что должно произойти, если две ссылки на объекты null
сравниваются для равенства значений. Неявное предположение заключается в том, что должен быть выброшен a NullPointerException
, но это не то, что делает метод ObjectUtils.equals(), который может считаться полезным методом утилиты.
Меня беспокоит, что Apache Commons, похоже, эффективно внедрил третью меру равенства в Java за дверью и что уже путаное положение дел могло быть значительно сложнее. Я называю это третьей мерой равенства, потому что он пытается проверить равенство значений, а когда это не удается, он возвращается к тестированию для ссылочного равенства. Тест равенства Apache Commons имеет много общего с равенством равенства и ссылочным равенством, но также совершенно другим.
Я прав, чтобы вас беспокоило, и я хочу, чтобы избежать использования ObjectUtils.equals()
, где это возможно?
Есть ли аргумент для утверждения, что ObjectUtils.equals()
обеспечивает полезный союз двух других мер равенства?
Выбранный ответ
По этому вопросу, похоже, нет консенсусного мнения, но я решил отметить Божо как правильно, потому что он лучше всего привлек мое внимание к тому, что я сейчас рассматриваю как самую большую проблему с нулевыми безопасными проверками на равные. Мы все должны писать отказоустойчивый код, который устраняет основную причину того, почему два нулевых объекта сравниваются для равенства значений, а не пытаются охватить проблему под ковром.
Ответы
Ответ 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 равным нулю, но это не похоже на большую проблему. По большей части я не ожидал, что мое приложение даже попадет в пути кода, которые включают тесты равенства, если один или несколько объектов равны нулю.