“比较方法违反了其一般合同”仅在某些情况下被抛出 [英] "Comparison method violates its general contract" is thrown only in certain cases

查看:131
本文介绍了“比较方法违反了其一般合同”仅在某些情况下被抛出的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

首先,我知道许多其他线程都描述了这个问题。但是我无法找到并回答这个问题,为什么不总是抛出这个错误?

First of all I know that this issue was described in many other threads. However I was not able to find and answer to the question, why this error is not always thrown?

让我来描述一下我的意思。我已经写了一些示例代码来说明这一点:

Let me describe what I mean. I have written some sample code to illustrate this :

public class Mushroom {

    public int size;

    public Mushroom(int size) {
        this.size = size;
    }

    @Override
    public boolean equals(Object obj) {
        //this is intentionally false - read in description
        return false;
    }
}

dsa

public class MushroomComparator implements Comparator<Mushroom> {

    @Override
    public int compare(Mushroom o1, Mushroom o2) {
        // here is the code which breaks the contract
         if (o1.size < o2.size){
             return 1;
         }else if(o1.size >o2.size){
             return -1;
         }
         return 1;
    }

}

最后测试比较:

public class ComparisonTest {
    public static void main(String[] args) {
//      System.setProperty("java.util.Arrays.useLegacyMergeSort", "true");
    List<Mushroom> forest = new ArrayList<>();

        for(int i =0; i<18; i++){
            Mushroom mushroom1 = new Mushroom(1);
            Mushroom mushroom2 = new Mushroom(3);
            Mushroom mushroom3 = new Mushroom(2);

            forest.add(mushroom1);
            forest.add(mushroom2);
            forest.add(mushroom3);

        }
        Collections.sort(forest, new MushroomComparator());
    }
}

在运行期间,我们将收到此描述的问题

During runtime we will receive this described issue


java.lang.IllegalArgumentException:比较方法违反了
一般合约!

java.lang.IllegalArgumentException: Comparison method violates its general contract!

根据 Collections.sort 方法:


(可选)如果实现检测到发现列表元素的自然顺序违反了可比较合同

(optional) if the implementation detects that the natural ordering of the list elements is found to violate the Comparable contract

所以让我们回答一下这个合同在可比较(在我的例子中我使用的是Comparator,但是从文档中它应该满足相同的要求)

So let's answer the question what is this contract in documentation of Comparable (in my example I use Comparator, but from the documentation it should fulfill the same requirements)


实现者必须确保所有x和y的sgn(x.compareTo(y))== -sgn(y.compareTo(x))

The implementor must ensure sgn(x.compareTo(y)) == -sgn(y.compareTo(x)) for all x and y



<这个规则我故意打破以获得我正在写的错误。这是compareTo方法的实现应该遵循的规则之一。其余的都在文档中描述,但一般来说,据我所知,文档等价关系应该得到满足

This rule I intentionally break to get error about which I'm writing about. This is one of the rule which implementation of compareTo method should follow. The rest of them are described in documentation, but generally speaking as I understand well documentation equivalence relation should be fulfilled


紧接着 compare for compareTo ,商是C上的等价关系,自然顺序是C上的总订单

It follows immediately from the contract for compareTo that the quotient is an equivalence relation on C, and that the natural ordering is a total order on C

现在真正困扰我的是我的测试方法中迭代次数变化的结果如果您将数字从18更改为22,那么将不会抛出异常。此异常被描述为可选,因此它确实意味着有时会抛出此异常,有时没有。我没有深入研究排序算法(TimSort)的新实现(自Java 7以来改变排序算法)。我明白,为了打破比较器合同,检查每组数据可能会耗费一些CPU消耗,但是有时候会有什么意图表明,有时甚至没有。它可能真的具有误导性。

What is now what really bothers me is a result of change to iterations number in my test method. If you change number from 18 to 22 then ... exception will not be thrown. This exception is described as Optional so it does mean that sometimes this exception will be thrown, and sometimes no. I was not diving deeply into new implementation of sorting algorithm (TimSort) (change of sort agorithm since Java 7). I understand that it could be mabye some CPU consuming to check every set of data for breaking comparator contract, but what is an intetion to sometimes shows that and sometimes no. It could be really missleading.

Morover我可以将比较方法的实现更改为简单..返回1.根据文档,它应该违反合同。但事实并非如此。
在文档中也有关于使用equals方法的合同但不是真的需要

Morover I can change the implementation of compare method to simply .. return 1. According to the documentation it should break the contract. But it isn't. In documentation stays also something about the contract with equals method but it not really needed


强烈建议,但不严格要求(x.compareTo(y)== 0)==(x.equals(y))

It is strongly recommended, but not strictly required that (x.compareTo(y)==0) == (x.equals(y))

并检查它在我的例子中,我实现了equals方法以返回始终为false。有了这个,我确信equals方法不会强制破坏比较器合同。

And to check it in my example I've implemented equals method to return always false. With this I was sure that equals method doesn't impose on breaking comparator contract.

现在我的问题是:比较器的真正合约是什么(在打破它的情况下)?为什么对于某些数据集会引发此异常,而对于其他数据则不会?也许我错过了什么?最后但并非最不重要的是 - 需要打破哪些规则以抛出此异常?

Now my question is : What is really contract of comparator (in context of breaking it) ? Why for some set of data this exception is thrown and for other not ? Maybe I'm missing something ? And last but not least - which rules exatcly need to be broken to throw this exception ?

请注意,解决此问题,可能会关闭这种新的排序实现算法此处,并在我的示例代码中进行了评论。

Just to note, solution for this, could be turning off this new implementation of sort algorithm what is described here and commented in my sample code.

推荐答案


为什么不总是抛出此错误

why this error is not always thrown

因为它是不是 Collections.sort 的工作来验证您的比较方法。它的工作只是实现排序。但这样做的逻辑可以揭示无效的比较方法作为其在某些条件分支中的逻辑的副产品。在这种情况下,抛出而不是尝试继续使用无效的比较方法进行排序是有意义的。

Because it's not the job of Collections.sort to validate your comparison method. Its job is simply to implement the sort. But the logic of doing so can reveal an invalid comparison method as a by-product of its logic in certain conditional branches. And in that case it makes sense to throw rather than attempting to continue to sort with an invalid comparison method.


什么是比较器的真正合约(在打破它的情况下)?

What is really contract of comparator (in context of breaking it) ?

如果你违反合同,排序可能无法正常运作或者根本没有。 (它将验证您的比较方法。)

That if you break the contract, sort may not function correctly, or at all. (Not that it will validate your comparison method.)


为什么某些数据集会抛出此异常而对于其他没有?

Why for some set of data this exception is thrown and for other not ?

如果排序没有遵循导致逻辑缺陷的路径,那么排序代码可以检测,它不会知道扔。但正在使用 TimSort 确实会发生逻辑分支,这会显示无效的比较方法,因此它会抛出。

If the sort doesn't happen to follow a path that leads to a logical flaw that the sorting code can detect, it won't know to throw. But the TimSort being used does happen to go down a logical branch which reveals the invalid comparison method, so it does throw.

这篇关于“比较方法违反了其一般合同”仅在某些情况下被抛出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆