Comparable и Comparator

Тема дорожной карты · Java

Comparable и Comparator — два Java-интерфейса, определяющие стратегии упорядочивания объектов и лежащие в основе сортировки в Collections Framework и Stream API. Comparable<T> реализуется непосредственно на сортируемом классе через переопределение compareTo(T other), устанавливая естественный порядок класса — String, Integer, LocalDate и все JDK-типы значений реализуют Comparable, поэтому они сортируются Collections.sort() или Arrays.sort() без дополнительной настройки. Comparator<T> — отдельный стратегический объект, определяющий внешний, специальный порядок, позволяя использовать несколько разных порядков сортировки для одного класса без его модификации; Java 8 обогатила Comparator цепочными фабричными методами вроде Comparator.comparing(Person::getLastName).thenComparing(Person::getFirstName).reversed(). Различие между Comparable и Comparator важно при работе с TreeSet, TreeMap и PriorityQueue, все из которых принимают необязательный Comparator в конструктор для переопределения естественного порядка, определённого Comparable. Поскольку Comparator является функциональным интерфейсом с единственным абстрактным методом compare(T o1, T o2), он естественно интегрируется с Lambda-выражениями и операцией sorted() Stream API, делая его центральной концепцией в современных Java Generics и функциональном программировании.

Как это работает

Comparable и Comparator даёт List (ArrayList, LinkedList), Set (HashSet, TreeSet, LinkedHashSet), Map (HashMap, TreeMap, LinkedHashMap, ConcurrentHashMap), Queue (ArrayDeque, PriorityQueue). Все реализуют Collection (Map отдельно). Streams API (stream(), filter(), map(), collect()) заменяет большинство явных циклов. Immutable factory-методы: List.of(...), Map.of(...), Set.of(...) — возвращают read-only view (бросают при мутации).

Когда применять

ArrayList по умолчанию вместо LinkedList — array-backed доступ драматически быстрее для почти любой реальной нагрузки. HashMap — кроме случаев, где важен порядок (LinkedHashMap для insertion order, TreeMap для sorted). ConcurrentHashMap — для shared-state map (никогда не оборачивайте HashMap в Collections.synchronizedMap в новом коде). Stream — для трансформаций; циклы — для side-effect-обработки.

Типичные ошибки

Ловушки Comparable и Comparator: выбор LinkedList для "быстрых insert" без замеров (cache-miss затмевает алгоритмическое преимущество); Map<String, ...> с mutable ключевыми объектами (hashCode меняется — потерянные entry); List.of(...) и попытка добавить позже (UnsupportedOperationException); concurrent modification в for-цикле (CME — используйте removeIf или Iterator).

Связанные понятия

Полезные ресурсы