Для упорядочивания объектов одного типа, хранящихся в массиве или коллекции, разработчики Java придумали интерфейс Comparable. В нём объявлен всего один метод, compareTo:

 public interface Comparable<T> {
    public int compareTo(T o);
}
Метод compareTo - 1Интерфейс Comparable параметризирован типом объекта, который он принимает в качестве параметра в метод compareTo. В данном случае мы предупреждаем компилятор, какие типы объектов собираемся сравнивать. Если условие идентичности типов не будет выполняться, то мы получим ошибку ClassCastException. Метод compareTo в Java сравнивает вызывающий объект с объектом, переданным в качестве параметра, и возвращает в результате выполнения сравнения целое число:
  • положительное, если вызывающий объект больше объекта, переданного в качестве параметра;
  • отрицательное, если вызывающий объект меньше объекта, переданного в качестве параметра;
  • нуль, если объекты равны.
Написание логики сравнения объектов – забота исключительно разработчика класса и определяется она желаемыми результатами при упорядочивании.

Зачем нужен метод compareTo в Java?

Программисту на Java очень часто приходиться иметь дело с массивами и списками объектов. При работе с большим количеством данных их зачастую удобно хранить в упорядоченном или отсортированном виде. Во-первых, это ускоряет работу с коллекцией при поиске нужной информации, во-вторых — упорядоченные данные визуально лучше воспринимаются.
Метод compareTo - 2
Одним из самых простых и эффективных способов отсортировать массив объектов является метод sort() класса Arrays, а коллекцию объектов в виде списка – аналогичный метод класса Collections. Для сортировки с помощью этих методов разработчики Java предоставили нам свободу в выборе способа задания критериев сортировки: с реализацией интерфейса Comparable в классе объектов, которые мы хотим упорядочить, или с использованием интерфейса Comparator. В первом случае методы сортировки принимают набор объектов в виде массива или списка:

sort(T[]array)//сортировка массива
sort(List<T> list)// сортировка списка
а во втором – плюс еще реализацию интерфейса Comparator:

sort(T[]array, Comparator <? super T> comparator)//сортировка массива
sort(List<T> list, Comparator <? super T> comparator)// сортировка списка
Интерфейс Comparable используется, когда мы хотим задать естественный (наиболее логичный с нашей точки зрения) порядок расположения объектов при сортировке. Он также является способом «зашить» алгоритм сравнения объектов этого класса на стадии его проектирования. Например, с помощью реализации этого интерфейса, определены критерии естественного упорядочивания в классах-обертках основных примитивных типов: Byte, Character, Long, Integer, Short, Double, Float, Boolean, String. Это также означает, что в этих классах есть реализованный метод compareTo, который при необходимости мы можем использовать в программе. Давайте посмотрим на примере сравнения строк, как реализован этот метод в классе String.

String str1="Аарон";
        String str2="АAPOH";
        String str3="аарон";
        String str4="ААрон";
        String str5="аАрон";
        String str6="Берта";
        String str7="берта";
String[] allStr=new String[]{str1,str2,str3,str4, str5,str6, str7};
        Arrays.sort(allStr);
        for (String s:allStr){
            System.out.println(s);
        }
    }
Если этот код выполнить в методе main, то получим такой результат:

АAPOH
ААрон
Аарон
Берта
аАрон
аарон
берта
Как видно из примера в классе String, метод compareTo упорядочивает строки в алфавитном порядке, лексикографически и с учетом регистра. Именно такой порядок сравнения строк определен разработчиками класса String как естественный. Для более простого понимания, что такое лексикографический порядок, достаточно вспомнить, как расположены слова в языковых словарях. При сравнении чисел объекты упорядочиваются в порядке возрастания. Такая логика сравнения заложена в классах Byte, Character, Long, Integer, Shor, Double, Float.

Реализуем сравнение в своем классе

Посмотрим на примере как можно встроить возможность сравнения объектов в свой класс. При реализации метода compareto Java мы можем задать один или несколько критериев упорядочивания объектов, а также задействовать методы compareto из классов String и Integer. Например, для объектов класса User мы задаем сортировку по имени, а в случае равенства имен – по возрасту. Объекты будут располагаться в естественном порядке (по мере увеличения значения). Класс User:

public class User  implements Comparable <User>{//добавляем возможность сравнивать объекты User

    private String name;
    private Integer age;
    private String email;

    public User(String name, int age, String email) {
        this.name = name;
        this.age = age;
        this.email = email;
    }

    @Override
//реализуем метод compareTo интерфейса Comparable
    public int compareTo(User o) {

//используем метод compareTo из класса String для сравнения имен
        int result = this.name.compareTo(o.name);

//если имена одинаковые -  сравниваем возраст,
используя метод compareTo из класса Integer
 
        if (result == 0) {
            result = this.age.compareTo(o.age);
        }
        return result;
    }

    @Override
    public String toString() {
        return "{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", email='" + email + '\'' +
                '}';
    }
Протестируем работу метода compareTo, реализованного в классе User, c помощью метода sort класса Collections:

public static void main(String[] args) {
    User user = new User("Андрей", 19, "andryha@mail.ru");
    User user2 = new User("Олег", 25, "oleg@mail.ru");
    User user3 = new User("Андрей", 24,"opr@google.com");
    User user4 = new User("Игорь", 16, "igor@mail.ru");
    User user5 = new User("Андрей", 44,"stary@google.com");
    List<User> list = new ArrayList<>();

    list.add(user);
    list.add(user2);
    list.add(user3);
    list.add(user4);
    list.add(user5);

    System.out.println("-------до сортировки--------");
    for (User u : list) {
        System.out.println(u);
    }
    System.out.println("-------после сортировки-----");
    Collections.sort(list);
    for (User u : list) {
        System.out.println(u);
    }
}
 }
}
Результат работы метода main:

-------до сортировки--------
{name='Андрей',  age=19,  email='andryha@mail.ru'}
{name='Олег',    age=25,  email='oleg@mail.ru'}
{name='Андрей',  age=24,  email='opr@google.com'}
{name='Игорь',   age=16,  email='igor@mail.ru'}
{name='Андрей',  age=44,  email='stary@google.com'}
-------после сортировки-----
{name='Андрей',  age=19,  email='andryha@mail.ru'}
{name='Андрей',  age=24,  email='opr@google.com'}
{name='Андрей',  age=44,  email='stary@google.com'}
{name='Игорь',   age=16,  email='igor@mail.ru'}
{name='Олег',    age=25,  email='oleg@mail.ru'}
Итак, подведем итог. Если вы — сторонник порядка во всем и хотите без лишнего кода расположить ваши объекты в массиве или списке – используете интерфейс Comparable. Реализация его метода compareTo позволяет достаточно легко встроить механизм естественного упорядочивания объектов вашего класса. Если вам приходится работать с коллекциями и массивами объектов стандартных классов, описанных в библиотеке Java, используйте уже готовые реализации compareTo в этих классах.