比较器导致 "Comparison method violates its general contract!" - 1300 项排序
Comperator caused "Comparison method violates its general contract!" - 1300 items sort
我有 1300 条数据,用我的计算机排序。当我使用 JAVA 6 时,排序工作正常。
当项目在 JAVA 7 上 运行 时,我收到此异常:
env: 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;
}
}
您的 collection 是否包含 null
?
如果是这样,则您的比较器存在一个问题:对于 null
,它总是 returns 0,因此 null
被认为等于所有内容。
作为 A > B
(前提)的结果,您还将有 A == null
和 null == B
因此通过传递性 A
和 B
也应该是相等,这违反了前提。
您需要为所有可能的值(包括 null
如果允许的话)建立一个完整且一致的顺序。
当您的 collection 包含混合类型(一些字符串、一些日期、一些 QuestionnaireStatusType)时,也会出现同样的问题。
我有 1300 条数据,用我的计算机排序。当我使用 JAVA 6 时,排序工作正常。 当项目在 JAVA 7 上 运行 时,我收到此异常:
env: 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;
}
}
您的 collection 是否包含 null
?
如果是这样,则您的比较器存在一个问题:对于 null
,它总是 returns 0,因此 null
被认为等于所有内容。
作为 A > B
(前提)的结果,您还将有 A == null
和 null == B
因此通过传递性 A
和 B
也应该是相等,这违反了前提。
您需要为所有可能的值(包括 null
如果允许的话)建立一个完整且一致的顺序。
当您的 collection 包含混合类型(一些字符串、一些日期、一些 QuestionnaireStatusType)时,也会出现同样的问题。