source

Java 오류: 비교 방법이 일반 계약을 위반합니다.

nicesource 2022. 12. 4. 22:32
반응형

Java 오류: 비교 방법이 일반 계약을 위반합니다.

저는 이에 대한 많은 질문을 보고 문제를 해결하려고 노력했지만, 1시간 동안 구글 검색과 많은 시행착오를 겪어도 여전히 수정이 되지 않습니다.여러분 중 몇몇은 그 문제를 알아채길 바랍니다.

내가 알 수 있는 건 이거야

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)
    ...

그리고 이것은 나의 대조군이다.

@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;
    }
}

감 잡히는 게 없어요?

예외 메시지는 실제로 매우 알기 쉬운 메시지입니다.계약서에 기재되어 있는 것은 이행성입니다.A > B ★★★★★★★★★★★★★★★★★」B > C 후, 임의의 ★★★★★★★★★★에 대해서A,B ★★★★★★★★★★★★★★★★★」CA > C종이와 연필로 확인해보니 당신의 코드에는 구멍이 거의 없는 것 같습니다.

if (card1.getRarity() < card2.getRarity()) {
  return 1;

않다-1card1.getRarity() > card2.getRarity().


if (card1.getId() == card2.getId()) {
  //...
}
return -1;

-1아이디 ' ' ' ' ' ' ' '''해야 .-1 ★★★★★★★★★★★★★★★★★」1어떤 아이디가 더 크냐에 따라 다르죠


이것 좀 봐.읽기 쉬울 뿐만 아니라 실제로 작동해야 한다고 생각합니다.

if (card1.getSet() > card2.getSet()) {
    return 1;
}
if (card1.getSet() < card2.getSet()) {
    return -1;
};
if (card1.getRarity() < card2.getRarity()) {
    return 1;
}
if (card1.getRarity() > card2.getRarity()) {
    return -1;
}
if (card1.getId() > card2.getId()) {
    return 1;
}
if (card1.getId() < card2.getId()) {
    return -1;
}
return cardType - item.getCardType();  //watch out for overflow!

다음 클래스를 사용하여 Comparator의 이동성 오류를 식별할 수 있습니다.

/**
 * @author Gili Tzabari
 */
public final class Comparators
{
    /**
     * Verify that a comparator is transitive.
     *
     * @param <T>        the type being compared
     * @param comparator the comparator to test
     * @param elements   the elements to test against
     * @throws AssertionError if the comparator is not transitive
     */
    public static <T> void verifyTransitivity(Comparator<T> comparator, Collection<T> elements)
    {
        for (T first: elements)
        {
            for (T second: elements)
            {
                int result1 = comparator.compare(first, second);
                int result2 = comparator.compare(second, first);
                if (result1 != -result2)
                {
                    // Uncomment the following line to step through the failed case
                    //comparator.compare(first, second);
                    throw new AssertionError("compare(" + first + ", " + second + ") == " + result1 +
                        " but swapping the parameters returns " + result2);
                }
            }
        }
        for (T first: elements)
        {
            for (T second: elements)
            {
                int firstGreaterThanSecond = comparator.compare(first, second);
                if (firstGreaterThanSecond <= 0)
                    continue;
                for (T third: elements)
                {
                    int secondGreaterThanThird = comparator.compare(second, third);
                    if (secondGreaterThanThird <= 0)
                        continue;
                    int firstGreaterThanThird = comparator.compare(first, third);
                    if (firstGreaterThanThird <= 0)
                    {
                        // Uncomment the following line to step through the failed case
                        //comparator.compare(first, third);
                        throw new AssertionError("compare(" + first + ", " + second + ") > 0, " +
                            "compare(" + second + ", " + third + ") > 0, but compare(" + first + ", " + third + ") == " +
                            firstGreaterThanThird);
                    }
                }
            }
        }
    }

    /**
     * Prevent construction.
     */
    private Comparators()
    {
    }
}

'이렇게 하다'를 돼요.Comparators.verifyTransitivity(myComparator, myCollection)을 사용하다

JDK 버전과도 관련이 있습니다.JDK6에서 정상적으로 동작할 경우 JDK7의 구현 방법이 변경되었기 때문에 JDK7에 문제가 있을 수 있습니다.

이것 좀 봐.

: 서서 by by by by by 가 사용하는 정렬 java.util.Arrays.sort by ( 적적적적적적 )java.util.Collections.sort아, 아, 아, 아, 아, 아, 아, 네.에서는, 「」를 하는 가 있습니다.IllegalArgumentException「」가 했을 경우.Comparable the the Comparable 에서는 이러한 했습니다.이전 구현은 이러한 상황을 묵살했다. 새 속성인 ""를 할 수 .java.util.Arrays.useLegacyMergeSort마지소트

나는 정확한 이유를 모른다.그러나 정렬을 사용하기 전에 코드를 추가하는 경우.괜찮을 거예요.

System.setProperty("java.util.Arrays.useLegacyMergeSort", "true");

다음 경우를 고려합니다.

ㅇㅇㅇㅇㅇ,o1.compareTo(o2)출됩니니다다card1.getSet() == card2.getSet()card1.getRarity() < card2.getRarity() 11을

ㅇㅇㅇㅇㅇㅇㅇㅇㅇㅇㅇ는,o2.compareTo(o1) 하다card1.getSet() == card2.getSet()그럼 이쯤에서 .else , , , 「 」card1.getId() == card2.getId()cardType > item.getCardType()을 다시 1번으로 하다

중에서 ★★★★★★★★★★★★★★★★★.o1 > o2 , , , , 입니다.o2 > o1당신은 계약을 어겼습니다.

        if (card1.getRarity() < card2.getRarity()) {
            return 1;

「」의 경우는, 「」입니다.card2.getRarity()card1.getRarity()-1을 반환하지 않을 수 있습니다.

당신도 마찬가지로 다른 사건들을 놓치셨군요나는 이렇게 할 것이다. 너는 너의 의도에 따라 바꿀 수 있다.

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());
    int comp=card1.getSet() - card2.getSet();
    if (comp!=0){
        return comp;
    }
    comp=card1.getRarity() - card2.getRarity();
    if (comp!=0){
        return comp;
    }
    comp=card1.getSet() - card2.getSet();
    if (comp!=0){
        return comp;
    }   
    comp=card1.getId() - card2.getId();
    if (comp!=0){
        return comp;
    }   
    comp=card1.getCardType() - card2.getCardType();

    return comp;

    }
}

것입니다.Comparator실행.이 문서를 체크함으로써 다음 명령어를 구현해야 합니다.compare(o1, o2)규칙을 준수하여 동등성 관계로서의 방법:

  • ifdisc는 a.disc(b)입니다.true thencompare는 「(a, b)」입니다.0
  • ifdev(0 a.dev(b)> 0then은 b.syslog(a)< 0 btrue
  • if b.timeout(0 a.timeout(b)> 0 † b.timeout(c)> 0thendisc > 은 a.disc(c) > 0 입니다.true

코드를 확인하여 고객의 구현이 하나 이상의 Comparator 계약 규칙을 위반하고 있는지 확인할 수 있습니다.정적 분석으로 찾기 어려운 경우 예외를 발생시킨 데이터를 사용하여 규칙을 확인할 수 있습니다.

, 요.n x 2 2D array '''contests2번으로 나누다의 경우 만, 의 입력에 가 발생했습니다 「 - 「 」 、 「 1 」 、 「 」

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

오류:-

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)

'어느 정도'라는 했어요.equals되는 항목, 작음으로 지정해야 .모든 경우에 대해 반환되는 항목(보다 큼, 같음, 작음)을 명시적으로 지정해야 합니다.

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

저도 같은 증상이 있었어요.스트림에서 정렬이 이루어지는 동안 다른 스레드가 비교 개체를 수정하고 있는 것으로 나타났습니다.이 문제를 해결하기 위해 객체를 불변의 임시 객체에 매핑하고 Stream을 임시 컬렉션으로 수집하여 정렬했습니다.

이 코드를 실행하려고 하면 다음과 같은 예외가 발생합니다.

    public static void main(String[] args) {
        Random random = new Random();
        List<Integer> list = new ArrayList<>();
        for (int i = 0; i < 50000; i++) {
            list.add(random.nextInt());
        }
        list.sort((x, y) -> {
            int c = random.nextInt(3);
            if (c == 0) {
                return 0;
            }
            if (c == 1) {
                return 1;
            }
            return -1;
        });
    }
Exception in thread "main" java.lang.IllegalArgumentException: Comparison method violates its general contract!
    at java.util.TimSort.mergeLo(TimSort.java:777)
    at java.util.TimSort.mergeAt(TimSort.java:514)
    at java.util.TimSort.mergeCollapse(TimSort.java:441)
    at java.util.TimSort.sort(TimSort.java:245)
    at java.util.Arrays.sort(Arrays.java:1512)
    at java.util.ArrayList.sort(ArrayList.java:1462)
    at Test.main(Test.java:14)

그 이유는 Comparator를 실장할 때 A > B > B > C > C > A의 케이스에 적합할 수 있으며 정렬 방식이 실행되어 깨지기 때문입니다.Java는 이 경우를 throw 예외로 방지합니다.

class TimSort<T> {
.
.
.
else if (len1 == 0) {
            throw new IllegalArgumentException(
                "Comparison method violates its general contract!");
.
.
.

결론적으로, 이 문제에 대처하기 위해.비교기가 A > B 및 B > C 및 C > A의 대소문자를 충족하지 않는지 확인해야 합니다.

몇 가지 기준(날짜, 같은 날짜, 기타...)에 따라 정렬해야 했습니다.이전 버전의 Java를 탑재한 이클립스에서는 동작하던 것이 안드로이드에서는 동작하지 않게 되었습니다.비교 방법은 계약을 위반하고 있습니다.

StackOverflow에서 읽은 후 날짜가 같으면 compare()에서 호출한 함수를 따로 작성했습니다.이 함수는 기준에 따라 우선순위를 계산하고 -1, 0 또는 1을 반환하여 비교()합니다.이제 된 것 같아요.

는 다음과 .StockPickBean. 하다

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);
    }
}

같은 에러가 발생했을 경우:

java.displaces를 클릭합니다.부정 인수예외:비교방법이 일반계약에 위배됩니다!

이 행을 변경했습니다.

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);

이것으로 에러가 해결됩니다.

다음과 같이 간단한 작업을 수행하는 것은 어떨까요?

int result = card1.getSet().compareTo(card2.getSet())
if (result == 0) {
    result = card1.getRarity().compareTo(card2.getRarity())
}
if (result == 0) {
    result = card1.getId().compareTo(card2.getId())
}
if (result == 0) {
    result = card1.getCardType().compareTo(card2.getCardType())
}
return result;

선호도 순으로 비교를 주문하면 됩니다.

언급URL : https://stackoverflow.com/questions/11441666/java-error-comparison-method-violates-its-general-contract

반응형