我正在使用Comparable
界面,发现当我将IllegalArgumentException
放入下面的程序时它正在抛出size=50
,当我放置size =5
时工作正常。
public class Test {
public static void main(String[] args) {
int size = 50;
Test compareTest = new Test();
compareTest.test(size);
}
public void test(int size) {
List<TestObject> requests = new ArrayList<TestObject>();
for (int index = 0; index < size; index++) {
TestObject request = new TestObject();
request.value = index;
requests.add(request);
}
Collections.sort(requests);
}
}
class TestObject implements Comparable<TestObject> {
public int value;
public int compareTo(TestObject req) {
if (value % 3 == 0) {
return -1;
} else if (value % 3 == 1) {
return 0;
}
return 1;
}
}
我不确定这个问题的根本原因,有人可以帮我解决这个问题。
下面给出了异常堆栈跟踪。
Exception in thread "main" java.lang.IllegalArgumentException: Comparison method violates its general contract!
at java.util.ComparableTimSort.mergeLo(ComparableTimSort.java:744)
at java.util.ComparableTimSort.mergeAt(ComparableTimSort.java:481)
at java.util.ComparableTimSort.mergeCollapse(ComparableTimSort.java:406)
at java.util.ComparableTimSort.sort(ComparableTimSort.java:213)
答案 0 :(得分:6)
您违反了可比较合同。
实际上你不比较它们之间的两个对象,但你只根据3的模数结果比较当前value
对象的TestObject
字段。你不使用{{ 1}}对象在TestObject
方法中作为参数传递。
假设您有compareTo()
个List
个TestObject
个对象3
为value
字段
这两个对象将返回-1
:
if (value % 3 == 0) {
return -1;
}
但根据规则:
实现者必须确保sgn(x.compareTo(y))== -sgn(y.compareTo(x))表示所有x和y。 (这意味着如果y.compareTo(x)抛出一个x.compareTo(y)必须抛出异常 异常。)
假设第一个对象是x
而第二个对象是y
如果y.compareTo(x)
返回负数(例如-1),那么x.compareTo(y)
应返回正数(例如1)。
我正在使用Comparable接口,发现它正在抛出 当我在下面的程序中输入size = 50时,IllegalArgumentException 当我把size = 5
时工作正常
事实上,当您违反Comparable
合同时,结果无法预测。它可能与某些特定值一起使用,不适用于其他特定值
它可能在特定的JVM版本中工作,而在另一个版本中不起作用
试图理解它失败的原因或者它对特定值的成功可能很有意思,但实际上没有用。
为了尊重合同,试图理解合同要好得多。
因为今天它的工作正在进行中,但明天在未来的实施中,它可能会改变。只有API才是保证。
答案 1 :(得分:2)
出现此错误是因为compareTo
不是合法比较功能。
compareTo
必须遵守等价(等式)和排序的数学规则:
(1)x.compareTo(x)
必须返回0.
(2)如果x.compareTo(y)
返回0,则y.compareTo(x)
返回0;如果x.compareTo(y)
返回&gt; 0,则y.compareTo(x)
返回&lt; 0,反之亦然。
(3)如果x.compareTo(y)
和y.compareTo(z)
都返回&gt; 0,那么x.compareTo(z)
也会返回&gt; 0;类似地,如果它们都是0,或者它们都是&lt; 0(传递性)。以上简化了一点。
你的比较函数甚至没有查看它的参数; compareTo
应该将一个对象与另一个对象进行比较,但是您的函数完全忽略了第二个参数。这清楚地表明您的比较函数将违反所有这三个条件。
Timsort有时会在违反合同时发出通知;如果它已经看过compareTo
如何对某些值起作用,它可能会推断它应该对以前看到的值有某种特定的行为方式。如果compareTo
返回它不期望的内容,则会抛出异常。大多数排序算法都不会寻找这种违规行为。但是如果它们被赋予了不遵守规则的比较函数,那么结果可能是一个相当随机的顺序,或者它可能会使算法陷入无限循环。