参考文献:
- 图解JDK7的Comparison method violates its general contract异常 http://blog.2baxb.me/archives/993
在用Collections.sort排序时出现了这个错误:Comparison method violates its general contract!
找了好久的问题,也没有找到最终解决方案,从网上查询,说是JDK7的问题
JDK7中的Collections.Sort方法实现中,如果两个值是相等的,那么compare方法需要返回0,否则可能会在排序时抛错,而JDK6是没有这个限制的。看TimSort.class中是在mergeHi方法这个位置报错的,这个方案里参数已经提示了:len2长度必须大于0
TimSort.class的源码:
/**
* Like mergeLo, except that this method should be called only if
* len1 >= len2; mergeLo should be called if len1 <= len2. (Either method
* may be called if len1 == len2.)
*
* @param base1 index of first element in first run to be merged
* @param len1 length of first run to be merged (must be > 0)
* @param base2 index of first element in second run to be merged
* (must be aBase + aLen)
* @param len2 length of second run to be merged (must be > 0)
*/
private void mergeHi(int base1, int len1, int base2, int len2) {
assert len1 > 0 && len2 > 0 && base1 + len1 == base2;
// Copy second run into temp array
T[] a = this.a; // For performance
T[] tmp = ensureCapacity(len2);
System.arraycopy(a, base2, tmp, 0, len2);
int cursor1 = base1 + len1 - 1; // Indexes into a
int cursor2 = len2 - 1; // Indexes into tmp array
int dest = base2 + len2 - 1; // Indexes into a
// Move last element of first run and deal with degenerate cases
a[dest--] = a[cursor1--];
if (--len1 == 0) {
System.arraycopy(tmp, 0, a, dest - (len2 - 1), len2);
return;
}
if (len2 == 1) {
dest -= len1;
cursor1 -= len1;
System.arraycopy(a, cursor1 + 1, a, dest + 1, len1);
a[dest] = tmp[cursor2];
return;
}
Comparator<? super T> c = this.c; // Use local variable for performance
int minGallop = this.minGallop; // " " " " "
outer:
while (true) {
int count1 = 0; // Number of times in a row that first run won
int count2 = 0; // Number of times in a row that second run won
/*
* Do the straightforward thing until (if ever) one run
* appears to win consistently.
*/
do {
assert len1 > 0 && len2 > 1;
if (c.compare(tmp[cursor2], a[cursor1]) < 0) {
a[dest--] = a[cursor1--];
count1++;
count2 = 0;
if (--len1 == 0)
break outer;
} else {
a[dest--] = tmp[cursor2--];
count2++;
count1 = 0;
if (--len2 == 1)
break outer;
}
} while ((count1 | count2) < minGallop);
/*
* One run is winning so consistently that galloping may be a
* huge win. So try that, and continue galloping until (if ever)
* neither run appears to be winning consistently anymore.
*/
do {
assert len1 > 0 && len2 > 1;
count1 = len1 - gallopRight(tmp[cursor2], a, base1, len1, len1 - 1, c);
if (count1 != 0) {
dest -= count1;
cursor1 -= count1;
len1 -= count1;
System.arraycopy(a, cursor1 + 1, a, dest + 1, count1);
if (len1 == 0)
break outer;
}
a[dest--] = tmp[cursor2--];
if (--len2 == 1)
break outer;
count2 = len2 - gallopLeft(a[cursor1], tmp, 0, len2, len2 - 1, c);
if (count2 != 0) {
dest -= count2;
cursor2 -= count2;
len2 -= count2;
System.arraycopy(tmp, cursor2 + 1, a, dest + 1, count2);
if (len2 <= 1) // len2 == 1 || len2 == 0
break outer;
}
a[dest--] = a[cursor1--];
if (--len1 == 0)
break outer;
minGallop--;
} while (count1 >= MIN_GALLOP | count2 >= MIN_GALLOP);
if (minGallop < 0)
minGallop = 0;
minGallop += 2; // Penalize for leaving gallop mode
} // End of "outer" loop
this.minGallop = minGallop < 1 ? 1 : minGallop; // Write back to field
if (len2 == 1) {
assert len1 > 0;
dest -= len1;
cursor1 -= len1;
System.arraycopy(a, cursor1 + 1, a, dest + 1, len1);
a[dest] = tmp[cursor2]; // Move first elt of run2 to front of merge
} else if (len2 == 0) {
throw new IllegalArgumentException(
"Comparison method violates its general contract!");//!!!这儿抛出的异常
} else {
assert len1 == 0;
assert len2 > 0;
System.arraycopy(tmp, 0, a, dest - (len2 - 1), len2);
}
}
报错代码源码:
List<Comparator<SalesSchemeOrderItemTreeVO>> comparators = new ArrayList<Comparator<SalesSchemeOrderItemTreeVO>>();
comparators.add(new Comparator<SalesSchemeOrderItemTreeVO>() {
@Override
public int compare(SalesSchemeOrderItemTreeVO o1, SalesSchemeOrderItemTreeVO o2) {
if(StringUtils.isNotBlank(o1.getSpaceCode()) && StringUtils.isNotBlank(o2.getSpaceCode())) {
return o1.getSpaceCode().compareTo(o2.getSpaceCode());
} else if(StringUtils.isNotBlank(o1.getSpaceName()) && StringUtils.isNotBlank(o2.getSpaceName())){
return o1.getSpaceName().compareTo(o2.getSpaceName());
} else {
return -1;
}
}
});
comparators.add(new Comparator<SalesSchemeOrderItemTreeVO>() {
@Override
public int compare(SalesSchemeOrderItemTreeVO o1, SalesSchemeOrderItemTreeVO o2) {
if(null == o1 || null == o2) {
return -1;
} else if(StringUtils.isNotBlank(o1.getProdCatId()) && StringUtils.isNotBlank(o2.getProdCatId())) {
return o1.getProdCatId().compareTo(o2.getProdCatId());
} else {
return -1;
}
}
});
comparators.add(new Comparator<SalesSchemeOrderItemTreeVO>() {
@Override
public int compare(SalesSchemeOrderItemTreeVO o1, SalesSchemeOrderItemTreeVO o2) {
if(StringUtils.isNotBlank(o1.getBrandGoodsIdName()) && StringUtils.isNotBlank(o2.getBrandGoodsIdName())) {
return o1.getBrandGoodsIdName().compareTo(o2.getBrandGoodsIdName());
} else {
return -1;
}
}
});
Collections.sort(itemTreeVO, new ComparatorChain(comparators));
这个问题目前我还是没有理解透,待理解透后再把具体的解决办法写出