105 votes

Erreur de Java : La méthode de comparaison viole son contrat général

J'ai vu beaucoup de questions à ce sujet, et j'ai essayé de résoudre le problème, mais après une heure de recherche sur Google et beaucoup d'essais et d'erreurs, je ne peux toujours pas le résoudre. J'espère que certains d'entre vous ont compris le problème.

Voilà ce que je reçois :

java.lang.IllegalArgumentException: Comparison method violates its general contract!
    at java.util.ComparableTimSort.mergeHi(ComparableTimSort.java:835)
    at java.util.ComparableTimSort.mergeAt(ComparableTimSort.java:453)
    at java.util.ComparableTimSort.mergeForceCollapse(ComparableTimSort.java:392)
    at java.util.ComparableTimSort.sort(ComparableTimSort.java:191)
    at java.util.ComparableTimSort.sort(ComparableTimSort.java:146)
    at java.util.Arrays.sort(Arrays.java:472)
    at java.util.Collections.sort(Collections.java:155)
    ...

Et voici mon comparateur :

@Override
public int compareTo(Object o) {
    if(this == o){
        return 0;
    }

    CollectionItem item = (CollectionItem) o;

    Card card1 = CardCache.getInstance().getCard(cardId);
    Card card2 = CardCache.getInstance().getCard(item.getCardId());

    if (card1.getSet() < card2.getSet()) {
        return -1;
    } else {
        if (card1.getSet() == card2.getSet()) {
            if (card1.getRarity() < card2.getRarity()) {
                return 1;
            } else {
                if (card1.getId() == card2.getId()) {
                    if (cardType > item.getCardType()) {
                        return 1;
                    } else {
                        if (cardType == item.getCardType()) {
                            return 0;
                        }
                        return -1;
                    }
                }
                return -1;
            }
        }
        return 1;
    }
}

Une idée ?

1voto

J'ai rencontré un problème similaire où j'essayais de trier une n x 2 2D array nommé contests qui est un tableau 2D d'entiers simples. Cela fonctionnait la plupart du temps, mais une erreur d'exécution s'est produite pour une entrée :-.

Arrays.sort(contests, (row1, row2) -> {
            if (row1[0] < row2[0]) {
                return 1;
            } else return -1;
        });

Erreur:-

Exception in thread "main" java.lang.IllegalArgumentException: Comparison method violates its general contract!
    at java.base/java.util.TimSort.mergeHi(TimSort.java:903)
    at java.base/java.util.TimSort.mergeAt(TimSort.java:520)
    at java.base/java.util.TimSort.mergeForceCollapse(TimSort.java:461)
    at java.base/java.util.TimSort.sort(TimSort.java:254)
    at java.base/java.util.Arrays.sort(Arrays.java:1441)
    at com.hackerrank.Solution.luckBalance(Solution.java:15)
    at com.hackerrank.Solution.main(Solution.java:49)

En regardant les réponses ci-dessus, j'ai essayé d'ajouter une condition pour equals et je ne sais pas pourquoi mais ça a marché. J'espère que nous devons spécifier explicitement ce qui doit être renvoyé pour tous les cas (supérieur à, égal à et inférieur à) :

        Arrays.sort(contests, (row1, row2) -> {
            if (row1[0] < row2[0]) {
                return 1;
            }
            if(row1[0] == row2[0]) return 0;
            return -1;
        });

1voto

Carl Rosenberger Points 901

J'ai eu le même symptôme. Pour moi, il s'est avéré qu'un autre thread modifiait les objets comparés pendant que le tri se déroulait dans un Stream. Pour résoudre le problème, j'ai mappé les objets vers des objets temporaires immuables, j'ai collecté le flux vers une collection temporaire et j'ai effectué le tri sur cette dernière.

1voto

Duloren Points 1024

L'origine de cette exception est une erreur Comparator mise en œuvre. Par vérifier la documentation nous devons mettre en œuvre le compare(o1, o2) en tant que méthode relation d'équivalence en suivant les règles :

  • if a.égale(b) est true then compare(a, b) est 0
  • if a.compare(b) > 0 then b.compare(a) < 0 est true
  • if a.compare(b) > 0 et b.compare(c) > 0 then a.compare(c) > 0 est true

Vous pouvez vérifier votre code pour vous rendre compte où votre implémentation enfreint une ou plusieurs règles du contrat du comparateur. S'il est difficile de le trouver par une analyse statique, vous pouvez utiliser les données qui ont généré l'exception pour vérifier les règles.

0voto

Jean Burkhardt Points 1

Je devais trier sur plusieurs critères (date, et, si même date ; autres choses...). Ce qui fonctionnait sur Eclipse avec une ancienne version de Java, ne fonctionnait plus sur Android : la méthode de comparaison viole le contrat ...

Après avoir lu sur StackOverflow, j'ai écrit une fonction séparée que j'appelle depuis compare() si les dates sont identiques. Cette fonction calcule la priorité, en fonction des critères, et renvoie -1, 0 ou 1 à compare(). Cela semble fonctionner maintenant.

0voto

pmkent Points 1

J'ai obtenu la même erreur avec une classe comme la suivante StockPickBean . Appelé à partir de ce code :

List<StockPickBean> beansListcatMap.getValue();
beansList.sort(StockPickBean.Comparators.VALUE);

public class StockPickBean implements Comparable<StockPickBean> {
    private double value;
    public double getValue() { return value; }
    public void setValue(double value) { this.value = value; }

    @Override
    public int compareTo(StockPickBean view) {
        return Comparators.VALUE.compare(this,view); //return 
        Comparators.SYMBOL.compare(this,view);
    }

    public static class Comparators {
        public static Comparator<StockPickBean> VALUE = (val1, val2) -> 
(int) 
         (val1.value - val2.value);
    }
}

Après avoir obtenu la même erreur :

java.lang.IllegalArgumentException : La méthode de comparaison viole son contrat général !

J'ai changé cette ligne :

public static Comparator<StockPickBean> VALUE = (val1, val2) -> (int) 
         (val1.value - val2.value);

à :

public static Comparator<StockPickBean> VALUE = (StockPickBean spb1, 
StockPickBean spb2) -> Double.compare(spb2.value,spb1.value);

Cela corrige l'erreur.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X