¿Puede alguien explicarme en términos simples, por qué este código arroja una excepción, "El método de comparación viola su contrato general!", Y ¿cómo lo soluciono?
private int compareParents(Foo s1, Foo s2) {
if (s1.getParent() == s2) return -1;
if (s2.getParent() == s1) return 1;
return 0;
}
java
comparator
n00bster
fuente
fuente
s1.getParent().equals(s2)
lugar des1.getParent() == s2
.s1
es el padre des2
, ys2
no es el padre des1
. EntoncescompareParents(s1, s2)
es0
, perocompareParents(s2, s1)
es1
. Eso no tiene sentido. (Además, no es transitivo, como aix se menciona a continuación.)Respuestas:
Tu comparador no es transitivo.
Dejar
A
ser el padre deB
, yB
ser el padre deC
. Puesto queA > B
yB > C
, entonces tiene que ser el caso de queA > C
. Sin embargo, si se invoca su comparadorA
yC
devolverá cero, lo que significaA == C
. Esto viola el contrato y por lo tanto arroja la excepción.Es bastante amable por parte de la biblioteca detectar esto y hacerle saber, en lugar de comportarse de manera errática.
Una forma de satisfacer el requisito de transitividad
compareParents()
es atravesar lagetParent()
cadena en lugar de solo mirar al antepasado inmediato.fuente
java.util.Arrays.sort
stackoverflow.com/questions/7849539/… deSolo porque esto es lo que obtuve cuando busqué en Google este error, mi problema fue que tuve
el
value >= other.value
debe (obviamente) ser en realidadvalue > other.value
por lo que en realidad se puede devolver 0 con objetos iguales.fuente
value
es un NaN (sivalue
es undouble
ofloat
), también fallaría.La violación del contrato a menudo significa que el comparador no proporciona el valor correcto o coherente al comparar objetos. Por ejemplo, es posible que desee realizar una comparación de cadenas y forzar cadenas vacías para ordenar hasta el final con:
Pero esto pasa por alto el caso en que AMBOS uno y dos están vacíos, y en ese caso, se devuelve el valor incorrecto (1 en lugar de 0 para mostrar una coincidencia), y el comparador informa que es una violación. Debería haber sido escrito como:
fuente
Incluso si su compareTo tiene la transitividad en teoría, a veces los errores sutiles arruinan las cosas ... como el error aritmético de coma flotante. Me pasó a mi. este fue mi código:
La propiedad transitiva se mantiene claramente, pero por alguna razón estaba obteniendo la IllegalArgumentException. ¡Y resulta que debido a pequeños errores en la aritmética de coma flotante, los errores de redondeo causaron que la propiedad transitiva se rompiera donde no deberían! Así que reescribí el código para considerar diferencias realmente pequeñas 0, y funcionó:
fuente
En nuestro caso, recibimos este error porque accidentalmente cambiamos el orden de comparación de s1 y s2. Así que ten cuidado con eso. Obviamente fue mucho más complicado que lo siguiente, pero esta es una ilustración:
fuente
Java no verifica la consistencia en un sentido estricto, solo le notifica si se encuentra con problemas serios. Además, no le da mucha información del error.
Estaba desconcertado con lo que está sucediendo en mi clasificador e hice una consistencia estricta Chequeador, tal vez esto lo ayude:
fuente
Compare
,Convert
(y potencialmente otros) no están definidos. Actualice el fragmento de código con un ejemplo autónomo.checkConsi(s)tency
y eliminar todas las@param
declaraciones redundantes para que el código sea más legible.En mi caso estaba haciendo algo como lo siguiente:
Lo que olvidé comprobar fue cuando tanto a.someField como b.someField son nulos.
fuente
He visto que esto sucede en un fragmento de código donde se realizó la comprobación a menudo recurrente de valores nulos:
fuente
Si
compareParents(s1, s2) == -1
entoncescompareParents(s2, s1) == 1
se espera. Con su código no siempre es cierto.Específicamente si
s1.getParent() == s2 && s2.getParent() == s1
. Es solo uno de los posibles problemas.fuente
Editar la configuración de VM funcionó para mí.
fuente
-
inicio de la solución propuesta. Tal vez quisiste algo así como una lista de viñetas de un elemento.No puede comparar datos de objetos de esta manera:
s1.getParent() == s2
esto comparará las referencias de objetos. Debería anular laequals function
clase Foo y luego compararlos asís1.getParent().equals(s2)
fuente