java.lang.IllegalArgumentException: O método de comparação viola seu contrato geral

Oi abaixo é o meu método de comparação do meu comparador. Não tenho certeza do que está errado. Eu procurei outras perguntas e respostas sobre o stack overflow, mas não tenho certeza do que está errado com o meu método, mas continuo recebendo java.lang.IllegalArgumentException: O método de comparação viola seu contrato geral!

Qualquer ajuda será muito apreciada

public int compare(Node o1, Node o2) { HashMap childMap = orderMap.get(parentID); if(childMap != null && childMap.containsKey(o1.getID()) && childMap.containsKey(o2.getID())) { int order1 = childMap.get(o1.getID()); int order2 = childMap.get(o2.getID()); if(order1order2) return 1; else return 0; } else return 0; } 

Adicionando a exceção estou recebendo

 java.lang.IllegalArgumentException: Comparison method violates its general contract! at java.util.TimSort.mergeLo(TimSort.java:747) at java.util.TimSort.mergeAt(TimSort.java:483) at java.util.TimSort.mergeCollapse(TimSort.java:410) at java.util.TimSort.sort(TimSort.java:214) at java.util.TimSort.sort(TimSort.java:173) at java.util.Arrays.sort(Arrays.java:659) at java.util.Collections.sort(Collections.java:217) 

Seu método compare() não é transitivo . Se A == B e B == C , então A deve ser igual a C

Agora considere este caso:

Para A , B e C , suponha que o método containsKey() retorne estes resultados:

  • childMap.containsKey(A.getID()) retorna true
  • childMap.containsKey(B.getID()) retorna false
  • childMap.containsKey(C.getID()) retorna true

Além disso, considere pedidos para A.getId() ! = B.getId() .

Assim,

  1. A e B retornariam 0 , como externo if condição for false => A == B
  2. B e C retornariam 0 , como externo if condição for false => B == C

Mas, A e C , poderia retornar -1 , ou 1 , com base no seu teste dentro do bloco if . Então, A != C Isso viola o princípio da transitividade.

Eu acho que você deve adicionar alguma condição dentro de seu bloco else , que executa uma verificação semelhante a como você faz em if bloquear.

Eu acho que o problema está no seu caso padrão. Considere o conjunto de nós A, B e C, em que os IDs são 'a' , 'b' e 'c' . Considere ainda que o seu childMap , que contém as informações relativas ao pedido, tenha o seguinte conteúdo:

 { 'a' => 1, 'c' => 3 } 

Agora, se você executar seu método de compare em A e B, retornará 0 , indicando que A e B são equivalentes. Além disso, se você comparar B e C, você ainda retornará 0 . No entanto, se você comparar A e C, você retornará -1 , indicando que A é menor. Isso viola a propriedade de transitividade do contrato do Comparator :

O implementador também deve assegurar que a relação é transitiva: ((compare(x, y)>0) && (compare(y, z)>0)) implica compare(x, z)>0 .

Finalmente, o implementador deve assegurar que compare(x, y)==0 implica que sgn(compare(x, z))==sgn(compare(y, z)) para todo z .

Você não pode tratar “itens que não têm um pedido atribuído” como tendo o valor “em algum lugar vagamente no meio”, já que os algoritmos de sorting não sabem onde colocá-los. Se você quiser ficar com essa abordagem, no caso em que o valor não está presente no mapa, você precisa atribuir um valor fixo para ser o número do pedido; algo como 0 ou MIN_INT é uma escolha razoável (mas qualquer escolha precisa ser documentada no Javadoc para compare !).