java比较方法违反了它的一般契约

标签 java comparison

使用自定义比较器进行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 的值不同

现在,如果您使用 ab 或使用 bc 调用比较方法,则比较方法对于两次调用都返回 0

为了满足传递性规则,如果使用 ac 调用比较方法,则还必须返回 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/

相关文章:

java - jackson 不匹配输入异常 : No content to map due to end-of-input

java - 如何通过用户输入的字符值过滤数组列表

image-processing - 方差分析可以用来比较两个图像吗?

mysql - Oracle RDBMS 是否比 MySQL RDBMS 更稳定、更安全、更健壮等?

java - 遍历图的顶点作为该顶点的方法

java - 使用属性文件中的属性值创建文件实例

java - 国际化(语言环境)在 java spring boot 中不使用重音符号

c++ - Boost StateCharts 与 Samek 的 "Quantum Statecharts"的比较

c - 搜索 vector 中出现两次的所有整数

c# - 跨平台开发的更好选择:Java还是C#?