Интерфейс Comparator
Часть раздела Объектно-ориентированное программирование путешествия по Java на Coddy — урок 45 из 87.
В то время как Comparable определяет естественный порядок сортировки класса, иногда вам нужно сортировать объекты различными способами. Интерфейс Comparator позволяет создавать отдельную логику сравнения без изменения исходного класса.
Comparator — это внешний объект, который сравнивает два объекта одного и того же типа. Это полезно, когда вам нужно несколько вариантов сортировки или когда вы не можете изменить сам класс:
import java.util.Comparator;
class NameComparator implements Comparator<Person> {
@Override
public int compare(Person p1, Person p2) {
return p1.getName().compareTo(p2.getName());
}
}
class AgeComparator implements Comparator<Person> {
@Override
public int compare(Person p1, Person p2) {
return p1.getAge() - p2.getAge();
}
}Затем вы можете передать компаратор в методы сортировки:
List<Person> people = new ArrayList<>();
people.add(new Person("Charlie", 30));
people.add(new Person("Alice", 25));
Collections.sort(people, new NameComparator()); // Сортировка по имени
Collections.sort(people, new AgeComparator()); // Сортировка по возрастуДля написания лаконичного кода вы можете использовать лямбда-выражения, так как Comparator является функциональным интерфейсом:
Collections.sort(people, (p1, p2) -> p1.getName().compareTo(p2.getName()));Ключевое отличие: Comparable реализуется самим сравниваемым классом и определяет один естественный порядок, в то время как Comparator является отдельным классом, который может определять неограниченное количество пользовательских порядков сортировки.
Задание
ЛегкоДавайте создадим систему сортировки сотрудников, которая демонстрирует возможности интерфейса Comparator. Вы создадите несколько компараторов для сортировки сотрудников различными способами — по зарплате и по имени — без изменения самого класса Employee.
Вы организуете свой код в четырех файлах:
Employee.java: Создайте класс, представляющий сотрудника с тремя приватными полями:name(String),department(String) иsalary(double). Включите конструктор для инициализации всех полей и методы-геттеры для каждого из них. ПереопределитеtoString(), чтобы он возвращал:[name] ([department]) - $[salary]SalaryComparator.java: Создайте компаратор, который сортирует сотрудников по зарплате в порядке убывания (сначала самые высокооплачиваемые). Реализуйте интерфейсComparator<Employee>и его методcompare(). ИспользуйтеDouble.compare()для безопасного сравнения значений зарплаты.NameComparator.java: Создайте еще один компаратор, который сортирует сотрудников по имени в алфавитном порядке возрастания (от A до Z). РеализуйтеComparator<Employee>и используйте методcompareTo()класса String для сравнения.Main.java: Объедините все вместе, создав список сотрудников и отсортировав их с помощью ваших компараторов. Вы получите входные данные для трех сотрудников, каждый на отдельной строке в формате:name,department,salaryСоздайте
ArrayListсотрудников, затем продемонстрируйте оба подхода к сортировке:- Сначала отсортируйте по зарплате, используя ваш
SalaryComparator, и выведите каждого сотрудника - Выведите пустую строку
- Затем отсортируйте по имени, используя ваш
NameComparator, и выведите каждого сотрудника
- Сначала отсортируйте по зарплате, используя ваш
Вы получите три строки входных данных, каждая из которых содержит данные о сотруднике в формате: name,department,salary
Например, строка ввода может выглядеть так: Alice,Engineering,75000.0
Не забудьте импортировать java.util.Comparator в файлах компараторов, а также java.util.ArrayList, java.util.Collections и java.util.Scanner в файле Main. Обратите внимание, как компараторы позволяют определять несколько стратегий сортировки извне — классу Employee не нужно ничего знать о том, как он может быть отсортирован!
Шпаргалка
Интерфейс Comparator позволяет создавать внешнюю логику сравнения для сортировки объектов без изменения исходного класса. Это полезно, когда вам нужно несколько вариантов сортировки.
Comparator сравнивает два объекта одного типа путем реализации метода compare():
import java.util.Comparator;
class NameComparator implements Comparator<Person> {
@Override
public int compare(Person p1, Person p2) {
return p1.getName().compareTo(p2.getName());
}
}Передайте компаратор в методы сортировки:
Collections.sort(people, new NameComparator());Вы можете использовать лямбда-выражения для более краткого кода, так как Comparator является функциональным интерфейсом:
Collections.sort(people, (p1, p2) -> p1.getName().compareTo(p2.getName()));Для сравнения числовых значений используйте методы классов-оберток, такие как Double.compare(), для безопасного сравнения:
class AgeComparator implements Comparator<Person> {
@Override
public int compare(Person p1, Person p2) {
return p1.getAge() - p2.getAge();
}
}Ключевое отличие: Comparable определяет один естественный порядок внутри самого класса, в то время как Comparator — это отдельный класс, который может определять неограниченное количество пользовательских порядков извне.
Попробуйте сами
import java.util.ArrayList;
import java.util.Collections;
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Прочитать данные о трех сотрудниках из ввода
// Формат каждой строки: имя,отдел,зарплата
String line1 = scanner.nextLine();
String line2 = scanner.nextLine();
String line3 = scanner.nextLine();
// TODO: Разобрать каждую строку и создать объекты Employee
// Подсказка: используйте split(",") для разделения значений
// TODO: Создать ArrayList сотрудников и добавить всех троих
// TODO: Отсортировать по зарплате, используя SalaryComparator, и вывести каждого сотрудника
// Подсказка: используйте Collections.sort(list, comparator)
// TODO: Вывести пустую строку
// TODO: Отсортировать по имени, используя NameComparator, и вывести каждого сотрудника
}
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыВведение в ООПКлассы и объектыКлючевое слово thisМетодыПоля (атрибуты)Метод-конструкторПерегрузка конструкторовИтоги — Простой калькулятор4Наследование
Основы наследования (extends)Ключевое слово superПереопределение методов (@Override)Цепочка конструкторовКласс ObjectОдиночное и многоуровневое наследованиеПочему нет множественного наследования классовИтоги — Иерархия сотрудников7Специальные методы и класс Object
Метод toString()equals() и hashCode()Метод clone()compareTo() и ComparableИнтерфейс ComparatorПовторение — Кастомная сортировка2Модификаторы доступа и инкапсуляция
Обзор уровней доступаМетоды геттеры и сеттерыСокрытие данныхКлючевое слово finalИтоги — Менеджер банковского счета5Полиморфизм
Основы перегрузки методовПереопределение методов (Run-Time)Upcasting и DowncastingОператор instanceofАбстрактные классы и методыИтоги: Калькулятор фигур8Продвинутые концепции ООП
Композиция против наследованияАгрегация против композицииВнутренние, вложенные и анонимные классыEnums и методы перечисленийRecords (Java 16+)Sealed-классы (Java 17+)11Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн BuilderПаттерн ObserverПаттерн Strategy3Свойства класса и статические члены
Переменные экземпляра и статические переменныеСтатические методыСтатические блокиКонстанты (static final)Итоги: Счетчик и утилиты6Интерфейсы и абстрактные классы
Введение в интерфейсыРеализация интерфейсовРеализация нескольких интерфейсовDefault и Static методы в интерфейсахАбстрактные классы vs ИнтерфейсыФункциональные интерфейсыИтоги — Платежная система9Обобщения
Введение в обобщенияОбобщенные классыОбобщенные методыОграниченные параметры типаСимволы подстановки (Wildcards: ?, extends, super)Итоги — Обобщенный контейнер12Паттерны проектирования. Часть 2
Паттерн «Команда»Паттерн «Адаптер»Паттерн «Декоратор»Паттерн «Шаблонный метод»Паттерн «Состояние»Паттерн «Компоновщик»Паттерн «Итератор»