JavaRush /Java блог /Java Developer /Метод compareTo
Автор
Владимир Портянко
Java-разработчик в Playtika

Метод compareTo

Статья из группы Java Developer
Для упорядочивания объектов одного типа, хранящихся в массиве или коллекции, разработчики 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 в этих классах.
Комментарии (22)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Денис Уровень 23
17 февраля 2022
Нужно пояснение.

     public int compareTo(User o) {
        int result = this.name.compareTo(o.name);

//если имена одинаковые -  сравниваем возраст,
используя метод compareTo из класса Integer

        if (result == 0) {
            result = this.age.compareTo(o.age);  
//сравнили возраст, получили какой-то результат
        }
        return result;
//вернули результат в compareTo, а дальше то что? 
    }
Что происходит дальше после возвращения результата в compareTo, какой дальнейший алгоритм сортировки?
Wiun Уровень 16
30 марта 2021
не совсем понимаю, что такое

//используем метод compareTo из класса String для сравнения имен
        int result = this.name.compareTo(o.name);
мы сравниваем переменную name из класса с какой переменной name? какое имя будет подставляться в аргумент "о"? и дальше. мы метод compareTo нигде не вызываем, а пользуемся Collections.sort так зачем мы его описывали и переопределяли?
Viktor Korotkov Уровень 23
22 декабря 2020
Не, ну почему если Андрюхе 44 - он сразу старый?😭
Артем Стукалов Уровень 23 Expert
5 июля 2020
Господи, почему же в гугле нормально всё объясняют с короткими и простыми примерами, а тут через Жопу ?
Daganet Уровень 22
17 апреля 2020
Поясните пж, почему не сортирует по возрасту? получается результат работы метода в этой статье не рабочий.
Denis Sidorenko Уровень 25
16 марта 2020
Например, с помощью реализации этого интерфейса, определены критерии естественного упорядочивания в классах-обертках основных примитивных типов: Byte, Character, Long, Integer, Short, Double, Float, Boolean, String. с каких пор String стал относится к примитивным типам?
GrinTea Уровень 16
26 февраля 2020
Как видно из примера в классе String, метод compareTo упорядочивает строки в алфавитном порядке, лексикографически и с учетом регистра. Я так понимаю что в статье опечатка. Написано метод compareTo, а должен быть повидимому .sort
Арсен Уровень 22
11 февраля 2020
приходится. а не приходиться. ПрихОдится работать и приходИться кому-либо братом/сватом.
Владимир Уровень 0
2 ноября 2018
Объясните, пожалуйста. Получается, что при использовании Collections.sort(). Метод compareTo выполняется автоматически? Мы ведь его не вызываем.