首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >获取java.lang.illegalArgumentException :比较方法违反了它的通用合同!使用比较器对列表进行排序时

获取java.lang.illegalArgumentException :比较方法违反了它的通用合同!使用比较器对列表进行排序时
EN

Stack Overflow用户
提问于 2018-07-29 05:01:13
回答 3查看 164关注 0票数 0

我正在尝试用Java语言以一种特定的方式对列表进行排序,我发现Comparator是一个很好的方法。

我将与你分享这个问题的伪代码。

我有一个DTO列表,假设我想按特定顺序的属性(字符串)对其进行排序,例如,以"Hi"开头的属性应该在顶部,其余的应该在下面。

下面是我的伪代码:

代码语言:javascript
复制
list.sort(new Comparator<myDto>(){

    @Override
    public int compare(myDto o1, myDto o2){
        if(o1.getProperty1() != null && o2.getProperty1() == null)
            return -1;
        else if(o1.getProperty1() == null && o2.getProperty1() != null)
            return 1;
        else if(o1.getProperty1().startsWith("Hi") && o2.getProperty1().startsWith("Hi"))
            return 0;
        else if(o1.getProperty1().startsWith("Hi") && !o2.getProperty1().startsWith("Hi"))
            return -1;
        return 1;

    }
});

我使用了我自己创建的4,5DTO来测试,但当我注入一个14kDTO的文件时,我得到了一个java.lang.illegalArgumentException

有什么想法吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2018-07-29 17:03:46

在其他答案中,您可以找到Comparator不工作的原因-简而言之,在末尾返回的1会使Comparator不一致(compare(a,b) != -compare(b,a))。

直接的Comparator实现很难写和读。这就是为什么在Java8中,您可以通过各种Comparator methods使用函数式方法。

将您的Comparator转换为函数式方法会产生以下结果:

代码语言:javascript
复制
Comparator<String> property1Comparator = Comparator.nullsLast(Comparator.comparing(
        property1 -> !property1.startsWith("Hi")
));
Comparator<MyDto> myDtoComparator = Comparator.comparing(MyDto::getProperty1, property1Comparator);

我认为这种方法比所有直接的Comparator实现更具可读性。

PS。如果您希望获得与Elliot's solution中相同的结果(它还会按自然顺序对没有以"Hi"为前缀的字符串进行排序),则需要以下property1Comparator

代码语言:javascript
复制
Comparator<String> property1Comparator = Comparator.nullsLast(Comparator.<String, Boolean>comparing(
        property1 -> !property1.startsWith("Hi")
).thenComparing(Comparator.naturalOrder()));
票数 3
EN

Stack Overflow用户

发布于 2018-07-29 06:27:12

在你的文本中,你说你希望那些对象以"Hi“开头,然后(小于)其他对象。此外,您的代码暗示您希望在末尾使用空值(比其他任何值都高)。因此,您的比较器必须考虑9种情况(Hi、non-Hi、o1与Hi的组合为null、non-Hi、o2为null ),并返回以下值:

代码语言:javascript
复制
o1=Hi:     0,-1,-1 for o2=Hi,non-Hi,null
o1=non-Hi: 1, 0,-1 for o2=Hi,non-Hi,null
o1=null:   1, 1, 0 for o2=Hi,non-Hi,null

您的代码不遵循该表,例如,对于非Hi/non-Hi,您将始终返回1而不是0,例如,当执行compare("Peter","John")compare("John","Peter")时。正如埃利奥特已经指出的那样,compare(a,b)compare(b,a)要么返回0,要么返回带有相反符号的结果,这一点至关重要。

附注:此表假设您不关心这三个组中的顺序。如果你想要一个,你可以用例如词法比较器的结果来代替零。

票数 3
EN

Stack Overflow用户

发布于 2018-07-29 15:43:08

你必须考虑这个a.compareTo(b) == -b.compareTo(a)。你的上一个测试只是假设如果其中任何一个以"Hi“开头,你就可以return 1,但这违反了上面的规则。你能做的就是这样。

代码语言:javascript
复制
list.sort((o1, o2) -> {
    String o1p1 = o1.getProperty1(), o2p1 = o2.getProperty1();

    boolean isNull1 = o1p1 == null, isNull2 = o2p1 == null;
    if (isNull1)
        return isNull2 ? 0 : -1;
    else if (isNull2)
        return +1;

    boolean o1p1hi = o1p1.startsWith("Hi"), o2p1hi = o1p1.startsWith("Hi");
    if (o1p1hi)
        return o2p1hi ? 0 : -1;
    else if (o2p1hi)
        return +1;

    return o1p1.compareTo(o2p1);
});
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51575229

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档