Comparison method violates its general contract! J

2019-01-06 14:28发布

I know this has been an issue for a while now, and checked all previously answers I could get, but still this one doesn't work.

The object 'crew' represents crewmembers with ranks and other items. The comparison should be made by comparing 'assigned_rank', an int value, and if this value is equal in both instances, then 'is_trainer', a boolean, should make the difference.

This method worked great as long as it was running with java < 7. But since Java 7 I keep getting this one:

java.lang.IllegalArgumentException: Comparison method violates its general contract!
at java.util.ComparableTimSort.mergeLo(ComparableTimSort.java:714)
at java.util.ComparableTimSort.mergeAt(ComparableTimSort.java:451)
at java.util.ComparableTimSort.mergeCollapse(ComparableTimSort.java:376)
at java.util.ComparableTimSort.sort(ComparableTimSort.java:182)
at java.util.ComparableTimSort.sort(ComparableTimSort.java:146)
at java.util.Arrays.sort(Arrays.java:472)
at java.util.Collections.sort(Collections.java:155)
at dormas_flightlog.Query.getCrew(Query.java:714)

Here is the source, where some potentially dangerous parts have allready been out-commented, but it still does not work:

public class crew implements Serializable, Comparable<crew> {

private static final long serialVersionUID = 36L;
private int flightID = 0;
private int assigned_rank = 25;
private boolean is_trainer = false;
...


@Override
public int compareTo(crew him) {

    int myRank = this.getAssigned_rank();
    int hisRank = him.assigned_rank;

    if (this == him) {
        return 0;
    }
    if (myRank > hisRank) {
        return 1;
    }
    if (myRank < hisRank) {
        return -1;
    }
    if (myRank == hisRank) {
//            if (is_trainer && !o.is_trainer) {
//                i = 1;
//            }
//            if (!is_trainer && o.is_trainer) {
//                i = -1;
//            }
//            if (is_trainer && o.is_trainer) {
//                i = 0;
//            }
//            if (!is_trainer && !o.is_trainer) {
//                i = 0;
//            }
        return 0;
    }

    return 0;
}

@Override
public int hashCode() {
    int hash = 7;
    hash = 31 * hash + this.assigned_rank;
    hash = 31 * hash + (this.is_trainer ? 1 : 0);
    return hash;
}

@Override
public boolean equals(Object o) {

    if (this == o) {
        return true;
    }


    int myRank = this.getAssigned_rank();
    int hisRank = 0;

    if (o instanceof crew) {
        crew him = (crew) o;
        hisRank = him.assigned_rank;
    } else {
        return false;
    }

    if (myRank > hisRank) {
        return false;
    }
    if (myRank < hisRank) {
        return false;
    }
    if (myRank == hisRank) {
//            if (is_trainer && !o.is_trainer) {
//                i = 1;
//            }
//            if (!is_trainer && o.is_trainer) {
//                i = -1;
//            }
//            if (is_trainer && o.is_trainer) {
//                i = 0;
//            }
//            if (!is_trainer && !o.is_trainer) {
//                i = 0;
//            }
        return true;
    }

    return false;
}

}

Implementing equals() was just a try to solve this problem. The given exception comes with or without equals(). I cannot see how the compareTo-method violates its contract. Any help is greatly appreciated....one day this code has to work with java 7 and I don't know how... Thanks

4条回答
何必那么认真
2楼-- · 2019-01-06 14:52

maybe you just have NaN values which you compare through Collections.sort(...), this has been a problem to me and I got that exception even having right implementation of compare(obj1, obj2) method! Check that!

查看更多
爷的心禁止访问
3楼-- · 2019-01-06 14:53

I was able to solve this error cause it was a bug in jdk7.

here I found the solution:

"Comparison method violates its general contract!" - TimSort and GridLayout

Basically i just had to add the

JAVA_OPTS="$JAVA_OPTS -Djava.util.Arrays.useLegacyMergeSort=true"

to my jboss

查看更多
劳资没心,怎么记你
4楼-- · 2019-01-06 14:53

Unfortunately, none of the solutions work for Android. TimSort is used deep in Android's ViewGroup relating to addChildrenForAccessibility that shows up under Java 7 & 8. No user code is involved in any comparison.

From other reports, it is related to having RelativeLayout with overlapping items as is commonly done. For example, a TextView that appears over an Image, or two items at the same location, where you only set one visible at a time. https://code.google.com/p/android/issues/detail?id=55933

I've not found any way around the bug. You can't set a -Djava option in Android Studio or Eclipse (at least that I could find). Forcing use of Java 1.6 should work, but doesn't. Seems like Amazon's newer Fire tablets and phones are far more sensitive to this bug than other devices.

There are rumors Java 9 will have a fix such as a run-time option that works, but with a bug that's been around for years, I have doubts it will ever be fixed - especially considering the animosity between Oracle and Google. Any yes, perhaps the bug is really deep in the Android code and should be fixed there. With more than a billion devices out there, that's not a viable solution for all the existing devices.

查看更多
劫难
5楼-- · 2019-01-06 15:09

see this:

From http://www.oracle.com/technetwork/java/javase/compatibility-417013.html#source

Area: API: Utilities Synopsis: Updated sort behavior for Arrays and Collections may throw an IllegalArgumentException

Description: The sorting algorithm used by java.util.Arrays.sort and (indirectly) by java.util.Collections.sort has been replaced. The new sort implementation may throw an IllegalArgumentException if it detects a Comparable that violates the Comparable contract. The previous implementation silently ignored such a situation. If the previous behavior is desired, you can use the new system property java.util.Arrays.useLegacyMergeSort, to restore previous mergesort behavior.

Nature of Incompatibility: behavioral

RFE: 6804124

For more detailed info, see the bug database reference here.

查看更多
登录 后发表回答