What is the difference between element sorting Comparable and Comparator?

Posted by cactuscake on Mon, 20 Dec 2021 19:21:02 +0100

This article has been included in my collection of articles: gitee.com/mydb/interv...

In the Java language, both Comparable and Comparator are used to sort elements, but they are essentially different. They are also common interview questions, so let's play it together today.

1. Different literal meanings

We first understand it from the literal meaning of the two. Comparable translates into Chinese as "comparison", while Comparator means "Comparator". Comparable ends with - able, indicating that it has certain abilities, while Comparator ends with - or, indicating that it is a comparison participant. This is to understand the difference between the two from the literal meaning.

2. Different usage

Both are top-level interfaces, but they have different methods and usages. Let's look at them separately.

2.1 Comparable

The Comparable interface has only one method compareTo. Implementing the Comparable interface and overriding the compareTo method can realize the sorting of a class. It supports collections Sort and arrays Sort. ​

When we do not use Comparable, the execution of the program is as follows:

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

import java.util.ArrayList;
import java.util.List;

public class ComparableExample {
    public static void main(String[] args) {
        // create object
        Person p1 = new Person(1, 18, "Java");
        Person p2 = new Person(2, 22, "MySQL");
        Person p3 = new Person(3, 6, "Redis");
        // Add to collection
        List<Person> list = new ArrayList<>();
        list.add(p1);
        list.add(p2);
        list.add(p3);
        // Print collection information
        list.forEach(p -> System.out.println(p.getName() +
                ": " + p.getAge()));
    }
}

// The following set/get/toString uses the annotations provided by lombok
@Getter 
@Setter
@ToString
class Person {
    private int id;
    private int age;
    private String name;

    public Person(int id, int age, String name) {
        this.id = id;
        this.age = age;
        this.name = name;
    }
}
Copy code

The program execution results are as follows:

As can be seen from the above figure, when the user-defined class Person does not implement Comparable, the List collection is not sorted, and only the insertion order of elements can be used as the output order. ​

However, at this time, the boss has a demand: you need to reverse the order according to the age attribute of the Person object, that is, sort according to the age attribute from large to small. At this time, you can invite the protagonist of our article: Comparable. ​

The use of Comparable is to implement the Comparable interface in the class of the custom object and override the compareTo method to implement the custom sorting rules. The specific implementation code is as follows:

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class ComparableExample {
    public static void main(String[] args) {
        // create object
        Person p1 = new Person(1, 18, "Java");
        Person p2 = new Person(2, 22, "MySQL");
        Person p3 = new Person(3, 6, "Redis");
        // Add object to collection
        List<Person> list = new ArrayList<>();
        list.add(p1);
        list.add(p2);
        list.add(p3);
        // Sort (according to the sorting rules defined in compareTo in the Person class)
        Collections.sort(list);
        // Order in output set
        list.forEach(p -> System.out.println(p.getName() +
                ": " + p.getAge()));
    }
}
//  The following set/get/toString are implemented using the annotations provided by lombok
@Getter
@Setter
@ToString
static class Person implements Comparable<Person> {
    private int id;
    private int age;
    private String name;

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

    @Override
    public int compareTo(Person p) {
        return p.getAge() - this.getAge();
    }
}
Copy code

The execution results of the program are shown in the following figure:

compareTo sorting method description

The parameter p received by the compareTo method is the object to be compared. The sorting rule is to compare the current object with the object to be compared, and then return an int type value. The sorting rule of positive order from small to large is: subtract the value of the object to be compared from the current object value; The reverse sorting rule from large to small is just the opposite: it subtracts the value of the current object from the value of the comparison object. ​

Note: if the custom object does not implement the Comparable interface, it cannot use collections For sorting by sort method, the compiler will prompt the following error:

2.2 Comparator

The sorting methods of Comparator and Comparable are different. compareTo is the sorting method of Comparable, while compare is the sorting method of Comparator. The specific implementation code is as follows:

import lombok.Getter;
import lombok.Setter;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class ComparatorExample {
    public static void main(String[] args) {
        // create object
        Person p1 = new Person(1, 18, "Java");
        Person p2 = new Person(2, 22, "MySQL");
        Person p3 = new Person(3, 6, "Redis");
        // Add object to collection
        List<Person> list = new ArrayList<>();
        list.add(p1);
        list.add(p2);
        list.add(p3);
        // Sort (according to the sorting rules defined in the person comparator)
        Collections.sort(list, new PersonComparator());
        // Order in output set
        list.forEach(p -> System.out.println(p.getName() +
                ": " + p.getAge()));
    }
}
/**
  * Comparator for Person class
  */
class PersonComparator implements Comparator<Person> {
    @Override
    public int compare(Person p1, Person p2) {
        return p2.getAge() - p1.getAge();
    }
}
@Getter
@Setter
class Person {
    private int id;
    private int age;
    private String name;

    public Person(int id, int age, String name) {
        this.id = id;
        this.age = age;
    }
}
Copy code

The execution results of the program are shown in the following figure:

Extension: Comparator anonymous class

Comparator can not only create a custom comparator, but also complete the function of custom comparator more quickly and conveniently through anonymous classes. The specific code is as follows:

import lombok.Getter;
import lombok.Setter;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

public class ComparatorExample {
    public static void main(String[] args) {
        // Build and add data
        List<Person> list = new ArrayList<>();
        list.add(new Person(1, 18, "Java"));
        list.add(new Person(2, 20, "MySQL"));
        list.add(new Person(3, 6, "Redis"));
        // Sort using the Comparator anonymous class
        list.sort(new Comparator<Person>() {
            @Override
            public int compare(Person p1, Person p2) {
                return p2.getAge() - p1.getAge();
            }
        });
        // Print set data
        list.forEach(p -> System.out.println(p.getName() +
                ": " + p.getAge()));
    }
}

@Getter
@Setter
static class Person {
    private int id;
    private int age;
    private String name;

    public Person(int id, int age, String name) {
        this.id = id;
        this.age = age;
        this.name = name;
    }
}
Copy code

The execution results of the program are shown in the following figure:

3. Different scenarios are used

Through the implementation code of the above example, we can see that the original class must be modified to use Comparable, that is, if you want to sort that class, you need to implement the Comparable interface and rewrite the compareTo method, so Comparable is more like an interface for "internal" sorting. ​

The use of comparator is different. Comparator does not need to modify the original class. That is, in the most extreme case, even if the Person class is provided by a third party, we can still realize the sorting function of the third party class Person by creating a new custom comparator comparator. In other words, the comparator interface can decouple from the original class and realize the sorting function without modifying the original class. Therefore, the comparator can be regarded as an "external" interface to provide sorting.

summary

Both Comparable and Comparator are used to sort elements. The differences between them are as follows:

  • Comparable means "compare" and Comparator means "Comparator";
  • Comparable implements sorting by rewriting compareTo method, while Comparator implements sorting by rewriting compare method;
  • Comparable must implement the sorting method internally by the custom class, while Comparator defines and implements sorting externally.

Therefore, summarize the difference between the two in one sentence: Comparable can be regarded as the "internal" sorting interface, while Comparator is the "external" sorting interface.

Topics: Java Back-end