Lak*_*ula 68 java migration compare comparator java-7
我看到很多关于这个的问题,并试图解决这个问题,但经过一个小时的谷歌搜索和大量的试验和错误,我仍然无法解决它.我希望你们中的一些人能够解决问题.
这就是我得到的:
java.lang.IllegalArgumentException: Comparison method violates its general contract!
at java.util.ComparableTimSort.mergeHi(ComparableTimSort.java:835)
at java.util.ComparableTimSort.mergeAt(ComparableTimSort.java:453)
at java.util.ComparableTimSort.mergeForceCollapse(ComparableTimSort.java:392)
at java.util.ComparableTimSort.sort(ComparableTimSort.java:191)
at java.util.ComparableTimSort.sort(ComparableTimSort.java:146)
at java.util.Arrays.sort(Arrays.java:472)
at java.util.Collections.sort(Collections.java:155)
...
Run Code Online (Sandbox Code Playgroud)
这是我的比较器:
@Override
public int compareTo(Object o) {
if(this == o){
return 0;
}
CollectionItem item = (CollectionItem) o;
Card card1 = CardCache.getInstance().getCard(cardId);
Card card2 = CardCache.getInstance().getCard(item.getCardId());
if (card1.getSet() < card2.getSet()) {
return -1;
} else {
if (card1.getSet() == card2.getSet()) {
if (card1.getRarity() < card2.getRarity()) {
return 1;
} else {
if (card1.getId() == card2.getId()) {
if (cardType > item.getCardType()) {
return 1;
} else {
if (cardType == item.getCardType()) {
return 0;
}
return -1;
}
}
return -1;
}
}
return 1;
}
}
Run Code Online (Sandbox Code Playgroud)
任何的想法?
Tom*_*icz 82
异常消息实际上非常具有描述性.这里所指的合同是传递:如果A > B
和B > C
那么对于任意的A
,B
和C
:A > C
.我用纸和笔检查了它,你的代码似乎有几个漏洞:
if (card1.getRarity() < card2.getRarity()) {
return 1;
Run Code Online (Sandbox Code Playgroud)
你不回-1
,如果card1.getRarity() > card2.getRarity()
.
if (card1.getId() == card2.getId()) {
//...
}
return -1;
Run Code Online (Sandbox Code Playgroud)
-1
如果id不相等,则返回.您应该返回-1
或1
取决于哪个ID更大.
看看这个.除了更具可读性之外,我认为它应该可行:
if (card1.getSet() > card2.getSet()) {
return 1;
}
if (card1.getSet() < card2.getSet()) {
return -1;
};
if (card1.getRarity() < card2.getRarity()) {
return 1;
}
if (card1.getRarity() > card2.getRarity()) {
return -1;
}
if (card1.getId() > card2.getId()) {
return 1;
}
if (card1.getId() < card2.getId()) {
return -1;
}
return cardType - item.getCardType(); //watch out for overflow!
Run Code Online (Sandbox Code Playgroud)
Gil*_*ili 34
您可以使用以下类来查明比较器中的传染性错误:
/**
* @author Gili Tzabari
*/
public final class Comparators
{
/**
* Verify that a comparator is transitive.
*
* @param <T> the type being compared
* @param comparator the comparator to test
* @param elements the elements to test against
* @throws AssertionError if the comparator is not transitive
*/
public static <T> void verifyTransitivity(Comparator<T> comparator, Collection<T> elements)
{
for (T first: elements)
{
for (T second: elements)
{
int result1 = comparator.compare(first, second);
int result2 = comparator.compare(second, first);
if (result1 != -result2)
{
// Uncomment the following line to step through the failed case
//comparator.compare(first, second);
throw new AssertionError("compare(" + first + ", " + second + ") == " + result1 +
" but swapping the parameters returns " + result2);
}
}
}
for (T first: elements)
{
for (T second: elements)
{
int firstGreaterThanSecond = comparator.compare(first, second);
if (firstGreaterThanSecond <= 0)
continue;
for (T third: elements)
{
int secondGreaterThanThird = comparator.compare(second, third);
if (secondGreaterThanThird <= 0)
continue;
int firstGreaterThanThird = comparator.compare(first, third);
if (firstGreaterThanThird <= 0)
{
// Uncomment the following line to step through the failed case
//comparator.compare(first, third);
throw new AssertionError("compare(" + first + ", " + second + ") > 0, " +
"compare(" + second + ", " + third + ") > 0, but compare(" + first + ", " + third + ") == " +
firstGreaterThanThird);
}
}
}
}
}
/**
* Prevent construction.
*/
private Comparators()
{
}
}
Run Code Online (Sandbox Code Playgroud)
只需Comparators.verifyTransitivity(myComparator, myCollection)
在失败的代码前调用即可.
Jus*_*ivi 30
它还与JDK版本有关.如果它在JDK6中运行良好,可能会在您描述的JDK 7中出现问题,因为jdk 7中的实现方法已经更改.
看这个:
描述:已经替换了java.util.Arrays.sort
(间接)使用的排序算法java.util.Collections.sort
.IllegalArgumentException
如果检测Comparable
到违反Comparable
合同的情况,新的排序实现可能会抛出.以前的实现默默地忽略了这种情况.如果需要先前的行为,则可以使用新的系统属性java.util.Arrays.useLegacyMergeSort
来恢复先前的mergesort行为.
我不知道确切的原因.但是,如果在使用sort之前添加代码.一切都会安好的.
System.setProperty("java.util.Arrays.useLegacyMergeSort", "true");
Run Code Online (Sandbox Code Playgroud)
考虑以下情况:
首先,o1.compareTo(o2)
被称为.card1.getSet() == card2.getSet()
碰巧是真的card1.getRarity() < card2.getRarity()
,所以你回来1.
然后,o2.compareTo(o1)
被叫.再次,card1.getSet() == card2.getSet()
是真的.然后,你跳到下面else
,然后card1.getId() == card2.getId()
恰好是真的,同样如此cardType > item.getCardType()
.你再次返回1.
从那起o1 > o2
,和o2 > o1
.你违反了合同.