简体   繁体   English

比较器排序

[英]Comparator Sorting

Please find the code below: 请在下面找到代码:

Collections.sort(longList, new Comparator<Long>() {
                        public int compare(long m1, long m2) {                          
                                return (int) (m2 - m1);                             
                            }

For some input it throws the following error: 对于某些输入,它将引发以下错误:

 java.lang.IllegalArgumentException: Comparison method violates its general contract!
        at java.util.TimSort.mergeLo(TimSort.java:763)
        at java.util.TimSort.mergeAt(TimSort.java:499)
        at java.util.TimSort.mergeForceCollapse(TimSort.java:442)
        at java.util.TimSort.sort(TimSort.java:239)
        at java.util.TimSort.sort(TimSort.java:189)
        at java.util.Arrays.sort(Arrays.java:867)
        at java.util.Collections.sort(Collections.java:229)

Please help! 请帮忙!

I'm assuming you have a typo in the question and the actual signature of the compare method is int compare(Long m1, Long m2) , or your code wouldn't pass compilation at all, which is not the issue you describe. 我假设您在该问题中有错字,并且compare方法的实际签名是int compare(Long m1, Long m2) ,否则您的代码根本不会通过编译,这不是您所描述的问题。

The actual issue is that you are trying to compare two longs by returning the difference between them cast to int . 实际的问题是,您试图通过将两个long的差值返回给int来比较两个long。 This may give you incorrect results when the difference is not within the range of the int type. 当差值不在int类型范围内时,这可能会给您带来不正确的结果。 You can use return m2.compareTo(m1) instead (or return m2 < m1 ? -1 : m2 > m1 ? 1 : 0 if you don't want to rely on Long 's compareTo implementation). 您可以改用return m2.compareTo(m1) (如果不想依赖LongcompareTo实现,则return m2 < m1 ? -1 : m2 > m1 ? 1 : 0 )。

Doing this: 这样做:

    Comparator<Long> d = new Comparator<Long>() {
        public int compare(long m1, long m2) {
            return (int) (m2 - m1);
        }
    };

is the same as NOT implementing the abstract method in the comparator interface 是一样的,在比较器接口NOT实现抽象方法

public int compare(T a1, T a2);

so your code is not compiling 所以你的代码没有编译

you should use (is java8) the method reference 您应该使用(是java8)方法参考

Comparator<Long> d = Long::compare;

but what is wrong whit this: (int) (m2 - m1); 但是这是怎么回事: (int) (m2 - m1); may you be asking yourself... 也许你在问自己...

well you are forcing a cast of 2 a long into a integer, so that result can be a very negative Long or a positive integer 好吧,您正在强制将2的long强制转换为整数,以便结果可以是非常负的Long或正整数

check this example to clarify: 检查此示例以澄清:

    long b = 1000_000_000_000_000L;
    long a = 100L;
    System.out.println(a - b);
    System.out.println((int) (a - b));

the result is as long 结果是一样长

-999999999999900 -999999999999900

as int 作为int

1530495076 1530495076

which is definitely breaking the comparation results 这肯定打破了比较结果

    List<Long> list = Arrays.asList(3L, 2L, 1L);

    list.sort(new Comparator<Long>() {
        @Override
        public int compare(Long o1, Long o2) {
            return o1.compareTo(o2);
        }
    });

    System.out.println(list);

OR: 要么:

    List<Long> list = Arrays.asList(3L, 2L, 1L);
    list.sort(Long::compareTo);
    System.out.println(list);

There are two things worth mentioning here: 这里有两件事值得一提:

  • you always use @Override when you write down a method of which you think should override something. 在写下您认为应该覆盖某些内容的方法时, 总是使用@Override。 Then the compiler can tell you when you got something wrong (as in your case, where the signature expects Long, but you used long) 然后,编译器会在出现问题时告诉您(例如,您的签名期望使用Long,但是您使用了long)
  • Avoid re-inventing the wheel, even when it is just for reversing the comparison. 即使只是为了反转比较,也要避免重新发明轮子。

In other words: instead of doing 换句话说:而不是做

int compare(Long l1, long l2) {
  return l2 - l1;

you could do: 你可以做:

  return l2.compareTo(l1);

instead. 代替。 That is just easier to read; 那更容易阅读; and performance is basically the same. 和性能基本相同。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM