Skip to content

5.11 Self 9.2

Comparator and comparable

Comparable is a logic that define how to compare, use compareTo

public class T implements Comparable<T> {
    @Override
    public int compareTo(T obj);

}

Comparator is a method to make object comparable.

public int compare(Object obj1, Object obj2):
Feature Comparator Comparable
Sorting Logic Location Defined externally Defined within the class (Internally)
Multiple Sorting Orders Supported Not supported
Interface Methods compare() compareTo()
Functional Interface Yes No
Usage Flexible and reusable Simple and tightly coupled

For example

This is a normal way to sort integer

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
//List is an interface that extends Collection interface  
//You need a concrete class that implements List
public class main {
    public static void main(String[] args) {
        List<Integer> numbers = new ArrayList<>();
        numbers.add(45);
        numbers.add(21);
        numbers.add(67);
        numbers.add(23);

        System.out.println("Before sorting: " + numbers);
        Collections.sort(numbers);
        System.out.println("After sorting: " + numbers);    

    }
}

Now, we want to sort these numbers according to the last digit, then we have two ways

1. Using Comparator

  1. The basic way

    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.Comparator;
    import java.util.List;
    //List is an interface that extends Collection interface  
    //You need a concrete class that implements List
    public class main {
    
        static class CompareByLastDigit implements Comparator<Integer> {
            @Override
            public int compare(Integer i, Integer j) {
                if (i % 10 < j % 10)
                    return -1;
                else
                    return 1;
            }
        }
    
        public static void main(String[] args) {
    
            Comparator<Integer> comparator = new CompareByLastDigit();
    
            List<Integer> numbers = new ArrayList<>();
    
            numbers.add(41);
            numbers.add(22);
            numbers.add(60);
            numbers.add(23);
    
            System.out.println("Before sorting: " + numbers);
            Collections.sort(numbers, comparator);
            System.out.println("After sorting: " + numbers);    
    
        }
    }
    
  2. Using anonymous class

    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.Comparator;
    import java.util.List;
    //List is an interface that extends Collection interface  
    //You need a concrete class that implements List
    public class main {
        public static void main(String[] args) {
    
            Comparator<Integer> comparator = new Comparator<Integer>() {
            public int compare(Integer i, Integer j) {
                if(i % 10 < j % 10)
                    return -1;
                else
                    return 1;
            }
        };
    
            List<Integer> numbers = new ArrayList<>();
    
            numbers.add(41);
            numbers.add(22);
            numbers.add(60);
            numbers.add(23);
    
            System.out.println("Before sorting: " + numbers);
            Collections.sort(numbers, comparator);
            System.out.println("After sorting: " + numbers);    
    
        }
    }
    
  3. Using lambda expression

    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.Comparator;
    import java.util.List;
    //List is an interface that extends Collection interface  
    //You need a concrete class that implements List
    public class main {
        public static void main(String[] args) {
    
            Comparator<Integer> comparator = (Integer i, Integer j) -> i % 10 < j % 10 ? -1 : 1;
    
            List<Integer> numbers = new ArrayList<>();
    
            numbers.add(41);
            numbers.add(22);
            numbers.add(60);
            numbers.add(23);
    
            System.out.println("Before sorting: " + numbers);
            Collections.sort(numbers, comparator);
            System.out.println("After sorting: " + numbers);    
    
        }
    }
    

2. Using Comparable

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
//List is an interface that extends Collection interface  
//You need a concrete class that implements List
public class main {

    static class LastDigitNumber implements Comparable<LastDigitNumber> {
        private int value;
        public LastDigitNumber(int value) { 
            this.value = value; 
        }
        @Override
        public int compareTo(LastDigitNumber other) { 
            return Integer.compare(this.value % 10, other.value % 10); 
        }
        @Override
        public String toString() { 
            return String.valueOf(value); 
        }
    }
    public static void main(String[] args) {
        List<LastDigitNumber> numbers = new ArrayList<>();
        numbers.add(new LastDigitNumber(41));
        numbers.add(new LastDigitNumber(22));
        numbers.add(new LastDigitNumber(60));
        numbers.add(new LastDigitNumber(23));
        System.out.println("Before sorting: " + numbers);
        Collections.sort(numbers);
        System.out.println("After sorting: " + numbers);    
    }
}

Now, we are given a more complex example

We have some students and want to sort students by age

  1. Using comparable

    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;
    //List is an interface that extends Collection interface  
    //You need a concrete class that implements List
    public class main {
    
        static class Student implements Comparable<Student> {
            private String name;
            private int age;
            public Student(String name, int age) {
                this.name = name;
                this.age = age;
            }
            @Override
            public int compareTo(Student other) {
                return Integer.compare(this.age, other.age);
            }
            @Override
            public String toString() {
                return name + "(" + age + ")";
            }
        }
        public static void main(String[] args) {
            List<Student> students = new ArrayList<>();
            students.add(new Student("Alice", 21));
            students.add(new Student("Bob", 19));
            students.add(new Student("Charlie", 22));
            students.add(new Student("Dave", 20));
            System.out.println("Before sorting: " + students);
            Collections.sort(students);
            System.out.println("After sorting: " + students);    
        }
    }
    
  2. Using Comparator

    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;
    import java.util.Comparator;
    //List is an interface that extends Collection interface  
    //You need a concrete class that implements List
    public class main {
    
        static class Student {
            public String name;
            public int age;
            public Student(String name, int age) {
                this.name = name;
                this.age = age;
            }
            @Override
            public String toString() {
                return name + "(" + age + ")";
            }
        }
        public static void main(String[] args) {
            List<Student> students = new ArrayList<>();
            Comparator<Student> comparator = (Student i, Student j) -> i.age < j.age ? -1 : 1;
            students.add(new Student("Alice", 21));
            students.add(new Student("Bob", 19));
            students.add(new Student("Charlie", 22));
            students.add(new Student("Dave", 20));
            System.out.println("Before sorting: " + students);
            Collections.sort(students, comparator);
            System.out.println("After sorting: " + students);    
        }
    }