【问题标题】:Comparison method violates its general contract - Java Error [duplicate]比较方法违反其一般合同-Java错误[重复]
【发布时间】:2021-12-05 03:01:31
【问题描述】:

我已经使用排序包装器定义了一个比较器。你能解释一下为什么这段代码会抛出一个异常,“比较方法违反了它的一般合同!”?如果您能告诉我如何解决它,我将不胜感激。

Ordering<Foo> order = new Ordering<Foo>() {

        @Override
        public int compare(Foo left, Foo right) {
                return getCompare(orderMap, left.getItemId(), right.getItemId());
        }
};

Collections.sort(Foos, order);

获取比较:

private int getCompare(Map<Long, Integer> orderMap, Long leftId, Long rightId) {

        int indexLeft = orderMap.get(leftId) == null ? -1 : orderMap.get(leftId);
        int indexRight = orderMap.get(leftId) == null ? -1 : orderMap.get(rightId);

        if (indexLeft < 0 || indexRight < 0) {
            return 1;
        }

        return Integer.compare(indexLeft, indexRight);

    }   

【问题讨论】:

标签: java exception collections comparison comparator


【解决方案1】:

这是合同:

  • 如果 `a.compare(b) 是 X,b.compare(c) 是 X,那么 a.compare(c) 也必须是 X,无论 X 是负数、正数还是零。
  • 如果a.compare(b) 是X,那么b.compare(a) 必须是-X:0 保持为0,-1 变为+1,等等。
  • a.compare(a) 必须为 0。

就是这样。您的比较方法在很多方面打破了这一点。例如,您的第二行中有一个错误(肯定是orderMap.get(rightId) == null,您可以改用getOrDefault 清理它),如果没有找到任何一个索引或小于0,您的代码总是返回1,这违反了规则(a.compare(b),其中 a 不在地图中,返回 1,b.compare(a) 也将返回 1。它需要返回一个负数)。

如果其中一个不在地图中,您将不得不想出一个规则来处理会发生什么。如果您的代码是在假设它不可能发生的情况下编写的,那么它是 - 当您的假设不成立时抛出异常,以便您可以调查为什么您的假设(所有提供的 left/rightIds 始终在地图中并且始终非负数)。正如所写的那样,如果发生这种情况,您的代码会以一种令人讨厌的方式直接上升——这就是异常的用途。以易于调试的方式展开。

如果那的意图,你将不得不制定一些规则。例如:如果a 在地图中但b 不在地图中,则a 始终高于b。这意味着if (indexLeft &lt; 0 &amp;&amp; indexRight &gt;= 0) return -1if (indexLeft &gt;= 0 &amp;&amp; indexRight &lt; 0) return +1;,以遵守规则。这就留下了一个问题:如果两者都没有怎么办。您可以选择没有办法订购它们(返回 0),但要知道这意味着您不能在 TreeMapTreeSet - 但是对列表进行排序,这很好。允许单独的不可比较的,它们最终会以任意顺序聚集在一起。这并不违反规则。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多