使用自定义比较器执行< code > Collection.sort using >时,我得到一个< code > Java . lang . illegalargumentexception:Comparison方法违反了它的一般约定
我理解这是一个问题,因为该方法是不可传递的。在我的比较器中,调用了多个方法,我确定了违反此规则的代码段。然而,我无法修复它,也看不到它的问题。
private int compareInstancesBelowChangeNumberStructureElements(ISapInstance pInstance1,
ISapInstance pInstance2) {
// Sort algorithm below change number structure elements
String[] tokens1 = pInstance1.getName().asString().split(COMPOUND_NAME_DELIMITER_REGEX);
String[] tokens2 = pInstance2.getName().asString().split(COMPOUND_NAME_DELIMITER_REGEX);
if ((tokens1 == null) || (tokens2 == null)) {
return 0;
}
int minLength = tokens1.length;
if (tokens2.length < minLength) {
minLength = tokens2.length;
}
if (minLength < 3) {
return 0;
}
// Compare criterion 1: node name or assembly group name
int compareValue = tokens1[2].compareTo(tokens2[2]);
if ((compareValue == 0) && (minLength >= 4)) {
// Compare criterion 2: class name
compareValue = tokens1[3].compareTo(tokens2[3]);
if (compareValue == 0) {
// Compare criterion 3: pos var name or assembly position name
compareValue = tokens1[1].compareTo(tokens2[1]);
if (compareValue == 0) {
// Compare criterion 4: instance name
compareValue = tokens1[0].compareTo(tokens2[0]);
}
}
}
return compareValue;
}
似乎是长度检查导致了这个问题,如果您正在检查长度以避免< code > arrayindexoutofboundsexception 。还有一种不涉及长度检查的方法。
static class Tokens implements Comparable<Tokens> {
private static final int N = 4;
// Order in which we would like to compare the tokens.
private static final int [] TOKEN_POS = {2, 3, 1, 0};
// Reordered tokens
private final String [] tokens = new String[N];
// The comparator used to compare each token
private final Comparator<String> cmp = Comparator.nullsFirst(String::compareTo);
Tokens(String []tokens) {
int i = 0;
for (int p : TOKEN_POS) {
// Place token to it's *correct* position
// put null if tokens does not have enough elements
this.tokens[i++] = p < tokens.length ? tokens[p] : null;
}
}
@Override
public int compareTo(Tokens o) {
for (int i = 0; i < N; i++) {
int c = cmp.compare(tokens[i], o.tokens[i]);
if (c != 0) return c;
}
return 0;
}
@Override
public String toString() {
return "Tokens{" +
"tokens=" + Arrays.toString(tokens) +
'}';
}
}
private static Tokens getCompareKey(String [] tokens) {
return new Tokens(tokens);
}
private static void compareAndPrint(Tokens k1, Tokens k2) {
System.out.println(k1 + " cmp " + k2 + " = " + k1.compareTo(k2));
}
public static void main(String [] args) {
Tokens key1 = getCompareKey(new String[]{"1", "2", "3"});
Tokens key2 = getCompareKey(new String[]{"1", "2", "3", "5"});
Tokens key3 = getCompareKey(new String[]{"1", "3"});
compareAndPrint(key2, key1);
compareAndPrint(key1, key3);
compareAndPrint(key2, key3);
}
输出
Tokens{key=[3, 5, 2, 1]} cmp Tokens{key=[3, null, 2, 1]} = 1
Tokens{key=[3, null, 2, 1]} cmp Tokens{key=[null, null, 3, 1]} = 1
Tokens{key=[3, 5, 2, 1]} cmp Tokens{key=[null, null, 3, 1]} = 1
很明显,这种方式的排序是可传递的。然而,它确实将令牌与最后一个令牌进行比较。您可以决定它是否适合您的应用程序。
想象一下ISapInance
有下一个令牌数量的情况。
a -> 4
b -> 2
c -> 4
它导致a=b
和b=c
(因为minL的长度
是2
),所以a
必须等于c
,但如果我们直接比较a
和c
,则不一定为真。
如果 ISapInstance.getName()
的令牌少于三个,则比较方法违反了传递性要求。
假设您有三个ISapInstance
实例:
现在,如果使用a
和b
或者使用b
和c
来调用比较方法,那么比较方法将为两个调用返回
为了满足传递性规则,如果使用a
和c
调用比较方法,则比较方法还必须返回
。但是,由于两者的名称都有两个以上的标记,并且
标记[2]
的值不同,因此如果按照所述的方式准备,它将返回与
0
不同的内容。
这三种情况会出现相同的问题:
(所有实例的令牌值相同[2])
标记[3]
值与要解决这个问题,如果只有一个实例的标记少于三个,或者第三个标记相同,而只有一个实例正好有三个标记,那么比较器不能返回< code>0。
例如:
private int compareInstancesBelowChangeNumberStructureElements(ISapInstance pInstance1,
ISapInstance pInstance2) {
// Sort algorithm below change number structure elements
String[] tokens1 = pInstance1.getName().asString().split(COMPOUND_NAME_DELIMITER_REGEX);
String[] tokens2 = pInstance2.getName().asString().split(COMPOUND_NAME_DELIMITER_REGEX);
if (tokens1.length < 3) {
return (tokens2.length < 3) ? 0 : -1;
} else if (tokens2.length < 3) {
return 1;
}
int minLength = tokens1.length;
if (tokens2.length < minLength) {
minLength = tokens2.length;
}
// Compare criterion 1: node name or assembly group name
int compareValue = tokens1[2].compareTo(tokens2[2]);
if (compareValue == 0) {
if (tokens1.length < 4) {
return (token2.length < 4) ? -1 : 0;
} else if (tokens2.length < 4) {
return 1;
} else {
// ... the remaining comparison operations
}
}
return compareValue;
}
一切似乎都运行良好(几天),但我只遇到了一次问题,并且很难重现该问题。 “比较方法违反了其总合同!”被抛出,完全让我措手不及。我有以下几点: 我的染色体类别: 我有一个ArrayList,我使用了两个Collections。排序(MyList)和集合。排序(MyList,Collections.reverseOrder())。到目前为止,他们仍在正常工作。我在100次跑步中只遇到过一次错误。这个实
问题内容: 您好,以下是我的比较器的比较方法。我不确定是什么问题。我在堆栈溢出时查找了其他类似标题的问题和答案,但不确定我的方法有什么问题,但我一直在获取java.lang.IllegalArgumentException:比较方法违反了它的一般约定! 任何帮助将不胜感激 添加我得到的异常 问题答案: 您的方法 不是可 传递的 。如果和,则必须等于。 现在考虑这种情况: 对于,和,假设方法返回以下
嗨,下面是我的比较器的比较方法。我不知道哪里出了问题。我查了关于堆栈溢出的其他类似标题的问题和答案,但不确定我的方法有什么问题,但我不断得到java.lang.IllegalArgument异常:比较方法违反了它的一般合同! 任何帮助将不胜感激 添加我得到的异常
我正在开发一个旧的应用程序,最初是在Java6编写的,几年前升级到Java7。 在这个应用程序中,我使用集合。通过实现接口,使用自定义方法对列表进行排序。列表中的对象类型是,它具有3个属性、和。 列表可以包含多个具有相同但具有唯一过期日期的对象。下面的比较函数按公司名称的升序对列表进行排序,并在同一公司名称列表中按过期日期的降序进行排序。下面是方法实现。 我知道,当在上面的比较方法实现中不满足可传
我想通过dateLastContact比较两个“收件人”,如果相同,就通过地址进行比较。这是我的代码: 而且我总是有这个错误: 我尝试了很多方法,但是现在,我不知道该怎么办。你能帮我吗? 收件人类别:
首先,很抱歉再次就这个话题提问。我很清楚这里有很多问题和答案。我已经读了其中的一些,但我的问题是我仍然不知道我做错了什么。这是我的代码: 看来我只是瞎了眼,看不到我的错误,所以如果你们中有人能帮我解决这个问题,我将非常感谢。 编辑:我想做的是确定一条线在左上角有0/0坐标的坐标系中是上、下、最左还是最右。这些点是double类型的。下面是错误消息: