获取java.lang.illegalArgumentException:比较方法违反了其一般约定!使用比较器对列表进行排序时

时间:2018-07-28 21:01:13

标签: java list sorting java-8 comparator

我正在尝试使用Java中的特定方式对列表进行排序,我发现Comparator是这样做的好方法。

我将与您分享问题的伪代码。

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

这是我的伪代码:

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、5个DTO来测试自己,但是当我注入14k DTO的文件时,我得到了java.lang.illegalArgumentException

有什么想法吗?

4 个答案:

答案 0 :(得分:4)

将最终的return 1更改为return o1.getProperty1().compareTo(o2.getProperty1()),JVM可以比较元素a, b b, a-如果最后只返回1,则您将总是违反总合同。

答案 1 :(得分:3)

在您的文本中,您说您想要那些以“ Hi”开头的对象早于(少于)其他对象。另外,您的代码暗示您最终希望空值(高于其他任何值)。因此,您的比较器必须考虑9种情况(Hi,non-Hi,对于o1为null以及Hi,non-Hi,对于o2为null)并返回以下值:

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

您的代码不在该表之后,例如对于非高/非高,您将始终返回1而不是0,例如同时进行compare("Peter","John")compare("John","Peter")时。正如Elliot已经指出的,至关重要的是compare(a,b)compare(b,a)要么返回0要么返回符号相反的结果。

P.S。该表假定您不关心这三个组中的顺序。如果您想要一个,则可以用例如的结果替换零词汇比较器。

答案 2 :(得分:2)

在其他答案中,您可以找到导致Comparator不起作用的解释-简而言之,您最后返回1会使Comparator不一致({{1} }。

直接compare(a,b) != -compare(b,a)实现很难编写和读取。这就是为什么在Java 8中,您可以通过各种Comparator methods使用功能性方法。

将您的Comparator转换为功能方法会产生:

Comparator

我相信这种方法比所有直接的Comparator<String> property1Comparator = Comparator.nullsLast(Comparator.comparing( property1 -> !property1.startsWith("Hi") )); Comparator<MyDto> myDtoComparator = Comparator.comparing(MyDto::getProperty1, property1Comparator); 实现方式更具可读性。

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

property1Comparator

答案 3 :(得分:1)

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

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);
});