Collections.sort(list) 和 Collections.sort(list,comparator) 的区别

Difference between Collections.sort(list) and Collections.sort(list,comparator)

有什么区别:

    public FlyingRabbit(){
        list = new ArrayList<Sellable>();
    }
    public void sort(Comparator<Sellable> comp) {
        Collections.sort(list, comp);
    }

和:

public class CompareCategory implements Comparator<Sellable> {
    @Override
    public int compare(Sellable s1, Sellable s2) {
            return (s1.getCategory()).compareTo(s2.getCategory());
    }
}

我很困惑为什么我需要使用比较器 comp 而不是在 CompareCategory.

中使用 compare

如果 Sellable 实现了 Comparable 接口,您可以使用 Collections.sort(list)。 否则你应该创建自己的 Comparator 并使用 Collections.sort(list, comparator)。因为必须有一个规则来比较 Sellable 类型的元素。

Collections.sort(List<T>) 按其元素的 natural ordering 对给定的 List 进行排序。对象的自然排序可以通过在相应的 class 中实现 Comparable 接口来定义。这个接口提供了一个方法,compareTo,returns

a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than the specified object.

另一方面,Collections.sort(List<T>, Comparator<T>) 根据给定的 ComparatorList 的元素进行排序。排序时将忽略它们的自然顺序。当 List 的元素已经拥有它们的自然顺序但我们想按不同的标准对它们进行排序时,第二种方法就派上用场了。

这是一个简单的示例,其中 Person class 显示姓名、姓氏和年龄。

class Person implements Comparable<Person> {
    private String name, lastName;
    private int age;

    public Person(String name, String lastName, int age) {
        this.name = name;
        this.lastName = lastName;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public String getLastName() {
        return lastName;
    }

    public int getAge() {
        return age;
    }

    @Override
    public int compareTo(Person o) {
        //Defining Person's natural ordering by creating a comparator and comparing by last name and then name the current object and the given paramter 
        return Comparator.comparing(Person::getLastName).thenComparing(Person::getName).compare(this, o);
    }

    @Override
    public String toString() {
        return String.format("%s %s %d", name, lastName, age);
    }

    public static void main(String[] args) {
        List<Person> list = new ArrayList<>(List.of(
                new Person("Matt", "O'Brien", 30),
                new Person("Conan", "O'Brien", 25),
                new Person("Frank", "Johnson", 50)
        ));

        //Original unordered list
        System.out.println(list);

        //List ordered by Person's natural ordering (last name and then name)
        Collections.sort(list);
        System.out.println(list);

        //List ordered by custom criteria (age)
        Collections.sort(list, Comparator.comparing(Person::getAge));
        System.out.println(list);
    }
}

当列表中包含的对象实现Comparable接口时,您不需要提供比较器

比较器与比较器

这就是documention定义这个接口的目的:

This interface imposes a total ordering on the objects of each class that implements it. This ordering is referred to as the class's natural ordering, and the class's compareTo method is referred to as its natural comparison method.

另一方面,比较器 - 是一个对象,用于为没有自然排序的对象集合提供排序,即没有明显的特定方式可以对这些对象进行排序,并且它们的 class 没有实现 Comparable.

当需要根据情况以不同方式对对象进行排序时,比较器很方便。例如,您有一个 class Student,学生可以按姓名、ID、成绩等进行排序。您可以通过创建 class 实现接口 Comparator 并覆盖方法 compare() (就像在您列出的代码中一样)或通过使用像 Java 8 引入的 Comparator.comparing() 这样的静态方法.

话虽如此,接口 ComparatorComparable 的用途相同(便于比较对象),但用例不同。

警告: 不要通过创建 比较器 inside compareTo() 方法,如另一个答案所示。这是个糟糕的主意。为什么?因为这样的实现将为该方法的每次调用创建一个 new comparator。要对 10.000.000 元素的列表进行排序,需要进行 10.000.000 * log(10.000.000) 次比较,每次比较都会调用 compareTo() 并且 comparator 的新实例将被调用被创建。它会对应用程序性能产生负面影响,因为创建对象的成本很高,它需要内存分配,然后给垃圾收集器带来大量工作。

流畅排序

为了对列表进行排序,您可以使用 Collections 实用程序 class 中的静态方法 sort(),它们自很早以来就是 JDK 的一部分版本。您可以在 Internet 上找到很多 code-snippets,其中使用了 Collection.sort()

使用 Java 8 方法 List#sort() 已在 List 接口中引入,您不再需要求助于 Collections class 中的静态方法.相反,您可以直接调用列表中的方法 sort(),请注意它始终需要一个比较器作为参数。如果列表的元素实现 Comparable 你应该传递 null 而不是:

If the specified comparator is null then all elements in this list must implement the Comparable interface and the elements' natural ordering should be used.

myList.sort(null); // only if element of the implement Comparable