Для упорядочивания объектов одного типа, хранящихся в массиве или коллекции, разработчики Java придумали интерфейс
Интерфейс
Одним из самых простых и эффективных способов отсортировать массив объектов является метод
Comparable
. В нём объявлен всего один метод, compareTo
:
public interface Comparable<T> {
public int compareTo(T o);
}

Comparable
параметризирован типом объекта, который он принимает в качестве параметра в метод compareTo
. В данном случае мы предупреждаем компилятор, какие типы объектов собираемся сравнивать. Если условие идентичности типов не будет выполняться, то мы получим ошибку ClassCastException
.
Метод compareTo
в Java сравнивает вызывающий объект с объектом, переданным в качестве параметра, и возвращает в результате выполнения сравнения целое число:
- положительное, если вызывающий объект больше объекта, переданного в качестве параметра;
- отрицательное, если вызывающий объект меньше объекта, переданного в качестве параметра;
- нуль, если объекты равны.
Зачем нужен метод compareTo в Java?
Программисту на Java очень часто приходиться иметь дело с массивами и списками объектов. При работе с большим количеством данных их зачастую удобно хранить в упорядоченном или отсортированном виде. Во-первых, это ускоряет работу с коллекцией при поиске нужной информации, во-вторых — упорядоченные данные визуально лучше воспринимаются.
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
в этих классах.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ