当前位置: 首页 > 知识库问答 >
问题:

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

洪博涛
2023-03-14

使用自定义比较器执行< 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;
  }

共有3个答案

司徒寒
2023-03-14

似乎是长度检查导致了这个问题,如果您正在检查长度以避免< 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

很明显,这种方式的排序是可传递的。然而,它确实将令牌与最后一个令牌进行比较。您可以决定它是否适合您的应用程序。

蒯卓君
2023-03-14

想象一下ISapInance有下一个令牌数量的情况。

a -> 4
b -> 2
c -> 4

它导致a=bb=c(因为minL的长度2),所以a必须等于c,但如果我们直接比较ac,则不一定为真。

卫阳炎
2023-03-14

如果 ISapInstance.getName() 的令牌少于三个,则比较方法违反了传递性要求。

假设您有三个ISapInstance实例:

    < li >名称包含三个标记元素的-- < li>b -具有包含两个标记元素的名称 < Li > c --其名称具有三个标记元素,并且其< code >标记[2]值不同于的值

现在,如果使用ab或者使用bc来调用比较方法,那么比较方法将为两个调用返回

为了满足传递性规则,如果使用ac调用比较方法,则比较方法还必须返回 。但是,由于两者的名称都有两个以上的标记,并且 标记[2]的值不同,因此如果按照所述的方式准备,它将返回与 0不同的内容。

这三种情况会出现相同的问题:

(所有实例的令牌值相同[2])

  • a-具有四个标记元素的名称
  • b-具有三个标记元素的名称
  • c-具有四个标记元素的名称,其标记[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类型的。下面是错误消息: