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

获取java.lang.illegalArgumentException:比较方法违反了它的一般约定!使用Comparator对列表进行排序时,java,list,sorting,java-8,comparator,Java,List,Sorting,Java 8,Comparator,我试图在Java中以一种特定的方式对列表进行排序,我发现Comparator是一种很好的方法 我将与大家分享这个问题的伪代码 我有一个DTO列表,假设我想按propertyString按特定顺序对其进行排序,例如,以Hi开头的属性应该在顶部,其余的应该在下面 这是我的伪代码: list.sort(new Comparator<myDto>(){ @Override public int compare(myDto o1, myDto o2){ if(

我试图在Java中以一种特定的方式对列表进行排序,我发现Comparator是一种很好的方法

我将与大家分享这个问题的伪代码

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

这是我的伪代码:

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


有什么想法吗?

将最终返回值1更改为返回值o1.getProperty1.compareToo2.getProperty1 JVM可以比较元素a、b或b、a-如果您在末尾返回1,那么您将始终违反一般约定。

在您的文本中,您说希望这些对象以Hi开头,而不是其他对象。此外,您的代码意味着您希望末尾的null值高于其他值。因此,你的比较器必须考虑9例HI,非HI,O1与HI,非HI,O2为零,并返回以下值:

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/非Hi,您总是返回1而不是0,例如,在执行comparePeter、John以及compareJohn、Peter时。正如Elliot已经指出的,comparea、b和compareb、a要么返回0,要么返回符号相反的结果,这一点至关重要

另外,该表假设您不关心三组中的顺序。如果你想要一个,你可以用一个词汇比较器的结果来代替零点。

你必须考虑A.CabReaToB==-B.COMPRATOTA。上一次测试只是假设如果其中一个以Hi开头,则可以返回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);
});

在其他答案中,您可以找到您的不起作用的解释-简而言之,您在末尾返回1会使比较器不一致comparea,b!=-B,a

直接比较器实现很难写入和读取。这就是为什么在Java8中,您可以使用函数式方法来使用不同的函数

将比较器转换为功能性方法可产生:

Comparator<String> property1Comparator = Comparator.nullsLast(Comparator.comparing(
        property1 -> !property1.startsWith("Hi")
));
Comparator<MyDto> myDtoComparator = Comparator.comparing(MyDto::getProperty1, property1Comparator);

这个问题本身可能是重复的,但这里有更多的错误:1。您可以也应该使用处理空案例。2.您应该非常小心,不要在排序映射中使用此比较器,因为它与equals不一致:即使对于a.equalsb==true不成立的对象,您也会返回0。谢谢Tomasz,我测试了所有答案,这些都是正确和清晰的,但我选择了你的,因为Functional方法更有效,更容易阅读。Thanx对于tour answer Ralf,它消除了我对我的比较器的所有疑虑,而且我测试了它,它工作得很好:Thanx对于tour answer Peter,我也测试了它,它工作得很好:对,Elliott,实际上,我的代码中缺少这一行:
Comparator<String> property1Comparator = Comparator.nullsLast(Comparator.<String, Boolean>comparing(
        property1 -> !property1.startsWith("Hi")
).thenComparing(Comparator.naturalOrder()));