Nooboolean
Nooboolean

Reputation: 43

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

What's the difference between:

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

and:

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

I'm confused about why do I need to use the Comparator comp instead of using compare inside CompareCategory.

Upvotes: 2

Views: 2455

Answers (3)

dani-vta
dani-vta

Reputation: 7070

Collections.sort(List<T>) sorts the given List according to the natural ordering of its elements. A class can define its natural ordering by implementing the Comparable interface. This interface provides a single method, compareTo(), which returns:

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

On the other hand, Collections.sort(List<T>, Comparator<T>) orders the elements of the List according to the given Comparator. The element's natural ordering is ignored. This second method comes in handy when the List's elements already exhibit a natural ordering, but we need to sort them by a different ordering.

Here's a brief example with a list of Person. The list is first sorted by Person's natural ordering (lastName and name), and then by a given Comparator that compares only by age.

class Person implements Comparable<Person> {

    private String name;
    private String lastName;
    private int age;

    // Defining Person's natural ordering by creating a comparator that compares by last name and name
    private static final Comparator<Person> naturalOrdering = Comparator.comparing(Person::getLastName).thenComparing(Person::getName);

    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) {
        return naturalOrdering.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("Luke", "O'Brien", 30),
                new Person("Conan", "O'Brien", 25),
                new Person("John", "Doe", 50)
        ));

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

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

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

Upvotes: 3

Alexander Ivanchenko
Alexander Ivanchenko

Reputation: 29028

You don't need to provide a comparator when objects contained in the list implement Comparable interface.

Comparator & Comparator

That's how the purpose of this interface defined by the 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.

On the other hand, comparator - is an object that is used to provide an ordering for collections of objects that don't have a natural ordering, i.e. there's no obvious specific way in which these object can be ordered, and their class doesn't implement Comparable.

Comparators are handy when objects are required to be ordered in differently depending on the situation. For instance, you have a class Student, and students can be sorted by their names, ids, grades, etc. And you can create a comparator for each of these cases either by creating a class implementing the interface Comparator and overrides method compare() (like in the code you've listed) or by making use of the static methods like Comparator.comparing() introduced with Java 8.

With that said, interfaces Comparator and Comparable serve the same purpose (to facilitate comparison of object), but have different use cases.

Caution: don't mix things together by creating a comparator inside the compareTo() method, as it's shown in another answer. It's a terrible idea. Why? Because such an implementation will create a new comparator for every invocation of this method. To sort a list of 10.000.000 elements, 10.000.000 * log(10.000.000) comparisons will be required, with each comparison compareTo() will be called and a new instance of comparator will be created. It'll have a negative impact on the application performance because creation of objects is costful, it requires memory allocation and then gives loads of work to the garbage collector.

Fluent sorting

In order to sort a list, you can use static methods sort() from the Collections utility class, that are part of the JDK since the very early version. And you could find lots code-snippets on the Internet, where Collection.sort() is being used.

With Java 8 method List#sort() was introduced in the List interface and you no longer need to resort to static methods from the Collections class. Instead you can directly invoke method sort() on the list, note that it always expects a comparator as an argument. If elements of the list implement Comparable you should pass null instead:

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

Upvotes: 0

yuri777
yuri777

Reputation: 377

If Sellable implements the interface Comparable you can use Collections.sort(list). Otherwise you should create own Comparator and use Collections.sort(list, comparator). Because there must be a rule by which to compare elements of the Sellable type.

Upvotes: 1

Related Questions