An article takes you to a deeper understanding of Comparable and Comparator

Posted by jerry_louise on Fri, 29 Oct 2021 06:11:43 +0200

Whenever a sort sensitive class is implemented, it should implement the Comparable interface so that its instances can be easily classified, searched, and used in comparison based collections

Whenever you compare field values in the comparTo method, you should avoid using the < and > operators. Instead, you should use the static compare method in the boxed basic type or the Comparator construction method in the Comparator interface

public class Test {
    public static void main(String[] args) {
        int a = 100;
        int b = 345;
        // Integer comparison
        System.out.println(Integer.compare(a,b));
        String str1 = "abc";
        String str2 = "abd";
        // Comparison of string types
        System.out.println(str1.compareTo(str2));
    }
}

1, Comparable

This interface forces an overall ordering of the objects of each class that implements it

This sort is called the natural sort of class, and the compareTo method of class is called its natural comparison method.

Whenever you compare field values in the comparTo method, you should avoid using the < and > operators. Instead, you should use the static compare method in the boxed basic type or the Comparator construction method in the Comparator interface

The list of objects (and arrays) that implement this interface can be automatically sorted through Collections.sort (and Arrays.sort).

Objects that implement this interface can be used as keys in an ordered map or elements in an ordered collection without specifying a comparator.

// TestDemo class
@Data
@Builder
public class TestDemo implements Comparable<TestDemo> {
    private String name;
    private Integer id;

    @Override
    public int compareTo(TestDemo o) {
        // Sort by name length
        // return this.name.length() - o.name.length();
        return Integer.compare(this.name.length(),o.name.length());
    }
}
public class Test {
    public static void main(String[] args) throws NoSuchMethodException {
        TestDemo demo1 = TestDemo.builder().name("l").id(1).build();
        TestDemo demo2 = TestDemo.builder().name("lll").id(1).build();
        TestDemo demo3 = TestDemo.builder().name("ll").id(2).build();
        List<TestDemo> list = new ArrayList<>();
        list.add(demo1);
        list.add(demo2);
        list.add(demo3);
        // Sort by name length from small to large
        Collections.sort(list);
        System.out.println(list);
    }
}

result:


Comparable can be considered as an internal comparator. One feature of the classes that implement the comparable interface is that these classes can be compared with themselves. As for how to compare with another class that implements the comparable interface, it depends on the implementation of the compareTo method, which is also called the natural comparison method.

If the developer add s a Collection object and wants the sort method of Collections to help you sort automatically, the object must implement the Comparable interface.

The return value of compareTo method is int. there are three cases:
(1) If the comparator is greater than the comparee (that is, the object in the compareTo method), a positive integer is returned
(2) If the comparator is equal to the comparee, 0 is returned
(3) If the comparator is smaller than the comparee, a negative integer is returned

2, Comparator

Comparator can be considered as an external comparator. There are two ways to implement comparator interface:

(1) An object does not support self comparison (it does not implement the Comparable interface), but it wants to compare two objects
(2) An object implements the Comparable interface, but developers think the comparison method in the compareTo method is not the one they want

There is a compare method in the Comparator interface. The method has two parameters, T o1 and T o2, which are generic representations, representing the two objects to be compared respectively. The return value of the method is int as in the Comparable interface. There are three cases:
(1) o1 is greater than o2 and returns a positive integer
(2) o1 equals o2 and returns 0
(3) o1 is less than o3 and returns a negative integer

// TestDemo class
@Data
@Builder
public class TestDemo {
    private String name;
    private Integer id;
}
public class Test {
    public static void main(String[] args) throws NoSuchMethodException {
        TestDemo demo1 = TestDemo.builder().name("l").id(1).build();
        TestDemo demo2 = TestDemo.builder().name("lll").id(1).build();
        TestDemo demo3 = TestDemo.builder().name("ll").id(2).build();
        List<TestDemo> list = new ArrayList<>();
        list.add(demo1);
        list.add(demo2);
        list.add(demo3);
        // Sort by name length from small to large
        list.sort(new Comparator<TestDemo>() {
            @Override
            public int compare(TestDemo o1, TestDemo o2) {
                return o1.getName().length() - o2.getName().length();
            }
        });
		// lambada expression abbreviation
        // list.sort((o1,o2)->o1.getName().length() - o2.getName().length());
        System.out.println(list);
    }
}

result:

It should be noted that for user-defined sorting, it must be a reference type, not a basic data type

For example, you cannot customize sorting

int[] arr = new int[]{1,3,2};

It's an integer

Integer[] arr = new Integer[]{1,3,2};

3, Comparison between the two

Interfaces can be used to compare and sort elements in the collection. Comparator is under package java.util, while Comparable is under package java.lang. the Comparable interface embeds the comparison code into its own class, and the latter implements comparison in an independent class.

JAVA encapsulated classes of basic types such as Integer and String have implemented the Comparable interface. These class objects themselves support self comparison. Directly calling Collections.sort() can sort the elements in the collection without implementing the Comparable interface.

For the List sequence of some custom classes, when the object does not support self comparison or the self comparison function cannot meet your requirements, you can write a Comparator to complete the size comparison between the two objects, that is, specify to use Comparator (Temporary Rule sorting, also known as special rule sorting). If Comparator is not specified, then use natural rule sorting, The natural order here is to implement the sorting method set by the Comparable interface

If a class implements the Camparable interface, it indicates that the objects of this class can be compared with each other, and the collection composed of this class object can be sorted directly by the sort method.

Comparator can be regarded as an implementation of algorithm, separating algorithm and data. Comparator can also be used in the following two environments:

  • The designer of class does not consider the comparison problem and does not implement Comparable. Sorting can be realized through Comparator without changing the object itself
  • To use a variety of sorting criteria, such as ascending, descending, etc

To sum up, there are two kinds of comparators, Comparable and Comparator. Compared with the former, the latter has the following advantages:

  • If the implementation class does not implement the Comparable interface and wants to compare the two classes (or the implementation class implements the Comparable interface, but is not satisfied with the comparison algorithm in the compareTo method), you can implement the Comparator interface, customize a Comparator and write a comparison algorithm
  • The way to implement the Comparable interface is more coupled than the way to implement the Comparator interface. If you want to modify the comparison algorithm, you need to modify the implementation class of the Comparable interface, and the class implementing the Comparator is compared externally, so there is no need to modify the implementation class.
    From this point of view, the way to implement the Comparable interface is not very good, especially when we type the. Class file of the implementation class into a. jar file for developers to use.
    In fact, the way to implement the Comparator interface will be described later as a typical policy pattern.

Topics: Java comparator