Может кто-нибудь объяснить мне простыми словами, почему этот код выдает исключение «Метод сравнения нарушает свой общий контракт!» И как мне это исправить?
private int compareParents(Foo s1, Foo s2) {
if (s1.getParent() == s2) return -1;
if (s2.getParent() == s1) return 1;
return 0;
}
java
comparator
n00bster
источник
источник
s1.getParent().equals(s2)
вместоs1.getParent() == s2
.s1
, что родительs2
, аs2
не родительs1
. ТогдаcompareParents(s1, s2)
есть0
, ноcompareParents(s2, s1)
есть1
. Это не имеет смысла. (Кроме того, он не транзитивен, как aix, упомянутый ниже.)Ответы:
Ваш компаратор не является переходным.
Позвольте
A
быть родителемB
, иB
быть родителемC
. Так какA > B
иB > C
, то это должно быть так , чтоA > C
. Однако, если ваш компаратор вызываетсяA
иC
, он будет возвращать ноль, что означаетA == C
. Это нарушает договор и, следовательно, создает исключение.Библиотеке довольно приятно обнаружить это и дать вам знать, а не вести себя беспорядочно.
Один из способов удовлетворить требование транзитивности
compareParents()
состоит в том, чтобы обходитьgetParent()
цепь, а не смотреть только на непосредственного предка.источник
java.util.Arrays.sort
stackoverflow.com/questions/7849539/…Просто потому, что это то, что я получил, когда я погуглил эту ошибку, моя проблема заключалась в том, что я имел
value >= other.value
должен (очевидно) на самом деле бытьvalue > other.value
так , что вы можете вернуть 0 с равными объектами.источник
value
является NaN (еслиvalue
этоdouble
илиfloat
), он также потерпит неудачу.Нарушение договора часто означает, что компаратор не предоставляет правильную или непротиворечивую стоимость при сравнении объектов. Например, вы можете выполнить сравнение строк и принудительно отсортировать пустые строки с помощью:
Но это упускает из виду случай, когда ОБА один и два пусты, и в этом случае возвращается неправильное значение (1 вместо 0, чтобы показать совпадение), и компаратор сообщает об этом как о нарушении. Это должно было быть написано как:
источник
Даже если ваш метод CompareTo поддерживает транзитивность в теории, иногда тонкие ошибки приводят в порядок… такие как арифметическая ошибка с плавающей запятой. Это случилось со мной. это был мой код:
Транзитивное свойство явно выполняется, но по какой-то причине я получил исключение IllegalArgumentException. И оказывается, что из-за крошечных ошибок в арифметике с плавающей точкой ошибки округления приводят к тому, что переходное свойство нарушается там, где не должно! Поэтому я переписал код, чтобы учесть действительно крошечные различия 0, и это сработало:
источник
В нашем случае мы получали эту ошибку, потому что мы случайно переключили порядок сравнения s1 и s2. Так что следите за этим. Это было очевидно намного сложнее, чем следующее, но это иллюстрация:
источник
В моем случае я делал что-то вроде следующего:
Что я забыл проверить, так это то, что a.someField и b.someField равны нулю.
источник
Java не проверяет согласованность в строгом смысле, а только уведомляет вас, если возникнут серьезные проблемы. Также это не дает вам много информации об ошибке.
Я был озадачен тем, что происходит в моем сортировщике, и сделал строгую последовательность проверки, может быть, это поможет вам:
источник
Compare
,Convert
(и потенциально другие) не определены. Пожалуйста, обновите фрагмент кода с помощью отдельного примера.checkConsi(s)tency
и удалить все избыточные@param
объявления, чтобы сделать код более читабельным.Я видел это в куске кода, где часто повторялась проверка на нулевые значения:
источник
Если
compareParents(s1, s2) == -1
тогдаcompareParents(s2, s1) == 1
ожидается. С вашим кодом это не всегда так.Конкретно если
s1.getParent() == s2 && s2.getParent() == s1
. Это всего лишь одна из возможных проблем.источник
Редактирование конфигурации VM работало для меня.
источник
-
начала предложенного решения. Возможно, вы намеревались создать что-то вроде списка из одного пункта.Вы не можете сравнивать данные объекта следующим образом:
s1.getParent() == s2
- это будет сравнивать ссылки на объекты. Вы должны переопределитьequals function
класс Foo, а затем сравнить их следующим образомs1.getParent().equals(s2)
источник