可比接口取决于大小?
Comparable interface depends upon size?
我正在处理 Comparable
接口,发现当我在下面的程序中放入 size=50
时它抛出 IllegalArgumentException
并且当我放入 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)
您违反了可比合同。
其实你并没有比较两个对象之间的关系,你只是根据对3取模的结果比较了当前TestObject
对象的value
字段。你没有使用TestObject
对象在 compareTo()
方法中作为参数传递。
假设您有一个 List
的两个 TestObject
对象,其中 3
作为 value
字段
两个对象会 return -1
:
if (value % 3 == 0) {
return -1;
}
但是根据规则:
The implementor must ensure sgn(x.compareTo(y)) ==
-sgn(y.compareTo(x)) for all x and y. (This implies that x.compareTo(y) must throw an exception iff y.compareTo(x) throws an
exception.)
假设第一个对象是x
,第二个对象是y
。
如果y.compareTo(x)
return是负数(比如-1),那么x.compareTo(y)
应该return是正数(比如1)。
I was working on Comparable interface and found that it is throwing
IllegalArgumentException when i put size=50 in the program below and
is working fine when i put size =5
事实上,当你违反Comparable
合同时,结果是不可预测的。它可能适用于某些特定值,不适用于其他特定值。
它可能适用于特定的 JVM 版本,但不适用于其他版本。
试图理解为什么它失败或成功的特定值可能很有趣,但实际上没有帮助。
努力理解合同以尊重它要好得多。
因为今天它正在运行,但明天在未来的实施中,它可能会改变。只有API是保证。
出现此错误是因为 compareTo
不是合法的比较函数。
compareTo
必须遵守等价(相等)和排序的数学规则:
(1) x.compareTo(x)
必须 return 0.
(2) 如果x.compareTo(y)
returns 0, y.compareTo(x)
returns 0;如果 x.compareTo(y)
returns >0,y.compareTo(x)
returns <0,反之亦然。
(3) 如果x.compareTo(y)
和y.compareTo(z)
都return>0,则x.compareTo(z)
也return>0;类似地,如果它们都为 0,或者它们都 < 0(传递性)。以上略作简化。
你的比较函数甚至不看它的参数; compareTo
应该将一个对象与另一个对象进行比较,但您的函数完全忽略了第二个参数。这清楚地表明您的比较函数将违反所有三个条件。
Timsort 有时会在合同被违反时注意到;如果它已经查看了 compareTo
如何处理某些值,它可能会推断它应该以某种方式处理它之前看到的值。如果 compareTo
return 是它不期望的东西,它会抛出异常。大多数排序算法不会寻找这种违规行为。但是如果给他们一个不遵守规则的比较函数,结果可能是一个相当随机的顺序,或者它可能会使算法陷入无限循环。
我正在处理 Comparable
接口,发现当我在下面的程序中放入 size=50
时它抛出 IllegalArgumentException
并且当我放入 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)
您违反了可比合同。
其实你并没有比较两个对象之间的关系,你只是根据对3取模的结果比较了当前TestObject
对象的value
字段。你没有使用TestObject
对象在 compareTo()
方法中作为参数传递。
假设您有一个 List
的两个 TestObject
对象,其中 3
作为 value
字段
两个对象会 return -1
:
if (value % 3 == 0) {
return -1;
}
但是根据规则:
The implementor must ensure sgn(x.compareTo(y)) == -sgn(y.compareTo(x)) for all x and y. (This implies that x.compareTo(y) must throw an exception iff y.compareTo(x) throws an exception.)
假设第一个对象是x
,第二个对象是y
。
如果y.compareTo(x)
return是负数(比如-1),那么x.compareTo(y)
应该return是正数(比如1)。
I was working on Comparable interface and found that it is throwing IllegalArgumentException when i put size=50 in the program below and is working fine when i put size =5
事实上,当你违反Comparable
合同时,结果是不可预测的。它可能适用于某些特定值,不适用于其他特定值。
它可能适用于特定的 JVM 版本,但不适用于其他版本。
试图理解为什么它失败或成功的特定值可能很有趣,但实际上没有帮助。
努力理解合同以尊重它要好得多。
因为今天它正在运行,但明天在未来的实施中,它可能会改变。只有API是保证。
出现此错误是因为 compareTo
不是合法的比较函数。
compareTo
必须遵守等价(相等)和排序的数学规则:
(1) x.compareTo(x)
必须 return 0.
(2) 如果x.compareTo(y)
returns 0, y.compareTo(x)
returns 0;如果 x.compareTo(y)
returns >0,y.compareTo(x)
returns <0,反之亦然。
(3) 如果x.compareTo(y)
和y.compareTo(z)
都return>0,则x.compareTo(z)
也return>0;类似地,如果它们都为 0,或者它们都 < 0(传递性)。以上略作简化。
你的比较函数甚至不看它的参数; compareTo
应该将一个对象与另一个对象进行比较,但您的函数完全忽略了第二个参数。这清楚地表明您的比较函数将违反所有三个条件。
Timsort 有时会在合同被违反时注意到;如果它已经查看了 compareTo
如何处理某些值,它可能会推断它应该以某种方式处理它之前看到的值。如果 compareTo
return 是它不期望的东西,它会抛出异常。大多数排序算法不会寻找这种违规行为。但是如果给他们一个不遵守规则的比较函数,结果可能是一个相当随机的顺序,或者它可能会使算法陷入无限循环。