Java Error: java.lang.IllegalArgumentException: Comparison method violates its general contract
Java Error: java.lang.IllegalArgumentException: Comparison method violates its general contract
我正在开发一个旧应用程序,它最初是用 Java 6 编写的,几年前升级到 Java 7。
在此应用程序中,我使用 Collection.Sort 通过实现 Comparator
接口,使用自定义 compare
方法对列表进行排序。列表中的对象类型为 CompanySchedule
,具有 3 个属性 companyName
、Schedule
和 expirationdate
。
列表可以包含多个具有相同 companyName
但具有唯一到期日期的对象。下面的比较函数按 companyName 的升序对列表进行排序,并在同一 companyName 列表中按截止日期的降序对列表进行排序。下面是方法实现。
public int compare(CompanySchedule c1, CompanySchedule c2) {
int returnVal = 0;
int value = c1.getCompany().getName().compareTo(c2.getCompany().getName());
if (value == 0){
if (c1.getUseExpirationDate() == null || c2.getUseExpirationDate() == null){
returnVal = -1;
}
else{
int chkdate = c1.getUseExpirationDate().compareTo(c2.getUseExpirationDate());
if (chkdate == 0){
returnVal = 0;
}
else if (chkdate > 0){
returnVal = -1;
}
else if (chkdate < 0){
returnVal = 1;
}
}
}
else if (value < 0){
returnVal = -1;
}
else if (value > 0){
returnVal = 1;
}
return returnVal;
}
我知道在上面的比较方法实现中不满足传递属性时报错
java.lang.IllegalArgumentException: Comparison method violates its general contract
会被抛出。
有人可以帮助确定此方法将在何处违反传递 属性。
感谢您的帮助。
我认为这里有一个问题:
if (c1.getUseExpirationDate() == null || c2.getUseExpirationDate() == null){
returnVal = -1;
}
如果 a.getUseExpirationDate() == null 并且 b.getUseExpirationDate() == null,您将得到 a < b 和 b < a,这意味着 a < a.
这破坏了一致性。
这个方法可能问题比较多,我没有全部检查过
祝你好运。
编辑
这段代码怎么样?
public int compare(CompanySchedule c1, CompanySchedule c2) {
int returnVal = 0;
int value = c1.getCompany().getName().compareTo(c2.getCompany().getName());
if (value == 0) {
if (c1.getUseExpirationDate() == null && c2.getUseExpirationDate() != null) {
returnVal = -1;
} else if (c1.getUseExpirationDate() != null && c2.getUseExpirationDate() == null) {
returnVal = 1;
} else if (c1.getUseExpirationDate() == null && c2.getUseExpirationDate() == null) {
returnVal = 0;
} else {
int chkdate = c1.getUseExpirationDate().compareTo(c2.getUseExpirationDate());
if (chkdate == 0) {
returnVal = 0;
} else if (chkdate > 0) {
returnVal = -1;
} else if (chkdate < 0) {
returnVal = 1;
}
}
} else if (value < 0) {
returnVal = -1;
} else if (value > 0) {
returnVal = 1;
}
return returnVal;
}
为了可比性,我尽量不改动太多,但应该重构一下。基本上它确定空值小于其他值。
我知道我来晚了,一旦我找到了我基本上忘记了我问过这个问题的解决方案。所以正如我提到的,根据我对 Collections 内部实现的理解,应用程序是在 Java 6 中编写的,然后升级到 Java 7
。
Sort 方法将使用的算法从 Merge 排序更改为 Tim Sort,Merge Sort 忽略了比较方法实现的传递性 属性,但是,Tim 排序要求比较方法实现是传递性的,否则上述异常会被抛出,因为我们有一个遗留应用程序,我们不想从代码中更改任何东西,所以我们在排序实现中使用 jvm
参数 java.util.Arrays.useLegacyMergeSort=true
内部合并排序
我正在开发一个旧应用程序,它最初是用 Java 6 编写的,几年前升级到 Java 7。
在此应用程序中,我使用 Collection.Sort 通过实现 Comparator
接口,使用自定义 compare
方法对列表进行排序。列表中的对象类型为 CompanySchedule
,具有 3 个属性 companyName
、Schedule
和 expirationdate
。
列表可以包含多个具有相同 companyName
但具有唯一到期日期的对象。下面的比较函数按 companyName 的升序对列表进行排序,并在同一 companyName 列表中按截止日期的降序对列表进行排序。下面是方法实现。
public int compare(CompanySchedule c1, CompanySchedule c2) {
int returnVal = 0;
int value = c1.getCompany().getName().compareTo(c2.getCompany().getName());
if (value == 0){
if (c1.getUseExpirationDate() == null || c2.getUseExpirationDate() == null){
returnVal = -1;
}
else{
int chkdate = c1.getUseExpirationDate().compareTo(c2.getUseExpirationDate());
if (chkdate == 0){
returnVal = 0;
}
else if (chkdate > 0){
returnVal = -1;
}
else if (chkdate < 0){
returnVal = 1;
}
}
}
else if (value < 0){
returnVal = -1;
}
else if (value > 0){
returnVal = 1;
}
return returnVal;
}
我知道在上面的比较方法实现中不满足传递属性时报错
java.lang.IllegalArgumentException: Comparison method violates its general contract
会被抛出。
有人可以帮助确定此方法将在何处违反传递 属性。 感谢您的帮助。
我认为这里有一个问题:
if (c1.getUseExpirationDate() == null || c2.getUseExpirationDate() == null){
returnVal = -1;
}
如果 a.getUseExpirationDate() == null 并且 b.getUseExpirationDate() == null,您将得到 a < b 和 b < a,这意味着 a < a.
这破坏了一致性。 这个方法可能问题比较多,我没有全部检查过
祝你好运。
编辑
这段代码怎么样?
public int compare(CompanySchedule c1, CompanySchedule c2) {
int returnVal = 0;
int value = c1.getCompany().getName().compareTo(c2.getCompany().getName());
if (value == 0) {
if (c1.getUseExpirationDate() == null && c2.getUseExpirationDate() != null) {
returnVal = -1;
} else if (c1.getUseExpirationDate() != null && c2.getUseExpirationDate() == null) {
returnVal = 1;
} else if (c1.getUseExpirationDate() == null && c2.getUseExpirationDate() == null) {
returnVal = 0;
} else {
int chkdate = c1.getUseExpirationDate().compareTo(c2.getUseExpirationDate());
if (chkdate == 0) {
returnVal = 0;
} else if (chkdate > 0) {
returnVal = -1;
} else if (chkdate < 0) {
returnVal = 1;
}
}
} else if (value < 0) {
returnVal = -1;
} else if (value > 0) {
returnVal = 1;
}
return returnVal;
}
为了可比性,我尽量不改动太多,但应该重构一下。基本上它确定空值小于其他值。
我知道我来晚了,一旦我找到了我基本上忘记了我问过这个问题的解决方案。所以正如我提到的,根据我对 Collections 内部实现的理解,应用程序是在 Java 6 中编写的,然后升级到 Java 7
。
Sort 方法将使用的算法从 Merge 排序更改为 Tim Sort,Merge Sort 忽略了比较方法实现的传递性 属性,但是,Tim 排序要求比较方法实现是传递性的,否则上述异常会被抛出,因为我们有一个遗留应用程序,我们不想从代码中更改任何东西,所以我们在排序实现中使用 jvm
参数 java.util.Arrays.useLegacyMergeSort=true
内部合并排序