比较者造成“比较方法违反了总合同!” - 1300项排序

时间:2015-01-27 09:57:22

标签: sorting java-7

我有1300个项目的数据,用我的comperator排序。当我使用JAVA 6时,排序工作正常。 当项目在JAVA 7上运行时,我得到了这个例外:

环境:JAVA 7,Vaadin 6.8.12,测试时发生了32位和64位相同的错误。 (它在JAVA 6上工作正常)

Caused by: 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)
    at com.vaadin.data.util.AbstractInMemoryContainer.doSort(AbstractInMemoryContainer.java:575)
    at com.vaadin.data.util.AbstractInMemoryContainer.sortContainer(AbstractInMemoryContainer.java:555)
    at com.vaadin.data.util.AbstractBeanContainer.sort(AbstractBeanContainer.java:440)
    at com.vaadin.ui.CustomTable.sort(CustomTable.java:4552)

这是我正在使用的兼容者:

private class StudyRecordComparator implements Comparator<Object> {

    @Override
    public int compare(Object o1, Object o2) {
        if (o1 instanceof String && o2 instanceof String) {
            return ((String) o1).compareToIgnoreCase(((String) o2));
        }
        else if (o1 instanceof QuestionnaireStatusType && o2 instanceof QuestionnaireStatusType) {
            QuestionnaireStatusType status1 = (QuestionnaireStatusType) o1;
            QuestionnaireStatusType status2 = (QuestionnaireStatusType) o2;
            if(status1.equals(status2)) {
                return 0;
            }
            switch(status1) {
                case WAITING_FOR_REVIEW :
                    return -1;

                case IN_REVIEW :
                    if(status2.equals(QuestionnaireStatusType.WAITING_FOR_REVIEW)) {
                        return 1;
                    } else {
                        return -1;
                    }
                case WAITING_PUBLICATION :
                    if(status2.equals(QuestionnaireStatusType.WAITING_FOR_REVIEW) || status2.equals(QuestionnaireStatusType.IN_REVIEW)) {
                        return 1;
                    } else {
                        return -1;
                    }
                case PUBLISHED :
                    if(status2.equals(QuestionnaireStatusType.WITHDRAWN)) {
                        return -1;
                    } else {
                        return 11;
                    }
                case WITHDRAWN :
                    return 1;

            }
        }
        else if (o1 instanceof Date && o2 instanceof Date) {
            return ((Date) o1).compareTo(((Date) o2));
        } else if (o1 instanceof Integer && o2 instanceof Integer) {
            return ((Integer) o1).compareTo(((Integer) o2));
        } else if (o1 instanceof User && o2 instanceof User) {
            return ((User)o1).toString().compareToIgnoreCase(((User)o2).toString());
        }

        return 0;
    }

}

public enum QuestionnaireStatusType {

IN_PROGRESS("In progress"), 
WAITING_FOR_REVIEW("Waiting for review"),
IN_REVIEW("In review"),
WAITING_PUBLICATION("Waiting for publication"),
PUBLISHED("Published"),
WITHDRAWN("Withdrawn");

private final String field;

public String getField() {
    return field;
}

QuestionnaireStatusType(String field){
    this.field = field;
}

}

1 个答案:

答案 0 :(得分:2)

您的收藏集是否包含null

如果是这样,比较器有一个问题:null总是返回0,因此null被视为等于一切。

作为A > B(前提)的结果,您还有A == nullnull == B,因此传递性AB也应该相等,这违反了前提。

您需要为所有可能的值建立一个完整且一致的排序(如果允许,则包括null)。

当您的集合包含混合类型(一些字符串,一些日期,一些QuestionnaireStatusType)时,会出现同样的问题。