使用自定义比较器进行Collection.sort
时,我收到java.lang.IllegalArgumentException:比较方法违反了其一般契约
我知道这是一个问题,因为该方法不可传递。在我的比较器中,调用了多个方法,并且我确定了违反此规则的代码段。但是我无法修复它,也无法看到它的问题。
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;
}
最佳答案
如果 ISapInstance.getName()
的标记少于三个,则您的比较方法违反了传递性要求。
假设您有三个 ISapInstance
实例:
- a - 名称包含三个标记元素
- b - 名称包含两个标记元素
- c - 名称包含三个 token 元素,其
token[2]
值与 a 的值不同
现在,如果您使用 a
和 b
或使用 b
和 c
调用比较方法,则比较方法对于两次调用都返回 0
。
为了满足传递性规则,如果使用 a
和 c
调用比较方法,则还必须返回 0
。但是,由于两者的名称都包含两个以上的标记,并且 token[2]
的值不同,如果按照描述的方式准备,它将返回与 0
不同的内容。
这三个实例也出现同样的问题:
(所有实例都具有相同的 token[2] 值)
- a - 名称包含四个标记元素
- b - 名称包含三个标记元素
- c - 名称包含四个 token 元素,其
token[3]
值与 a 的值不同
要解决此问题,如果只有一个实例的 token 少于三个,或者第三个 token 相同且只有一个实例恰好有三个 token ,则比较器不得返回 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;
}
关于java比较方法违反了它的一般契约,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40389926/