Сортировка с Comparator и лямбда-выражениями
Создавайте экземпляры Comparator с помощью лямбда-выражений и фабричных методов Comparator.comparing.
«Сортировка с Comparator и лямбда-выражениями» — бесплатный урок Java Academy на CoddyKit. Это урок 2 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Java Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Java Academy содержит 4 уроков всего.
Comparator и сортировка с помощью лямбда-выражений
Comparator<T> задаёт внешний порядок объектов. В отличие от интерфейса естественного сравнения, можно создать любое количество Comparator, не изменяя класс.
Создание Comparator
Создайте Comparator с помощью лямбда-выражения или ссылки на метод и передайте его методам sort.
import java.util.*;
record Product(String name, double price, int stock) {}
List<Product> products = new ArrayList<>(List.of(
new Product("Mouse", 29.99, 50),
new Product("Laptop", 999.00, 5),
new Product("USB Hub", 24.99, 100)
));
// Lambda comparator
products.sort((a, b) -> Double.compare(a.price(), b.price()));
System.out.println(products);
// [USB Hub, Mouse, Laptop] (by price ascending)Фабрика Comparator.comparing
Comparator.comparing(keyExtractor) создаёт Comparator из функции извлечения ключа — это чище, чем необработанные лямбда-выражения.
import java.util.Comparator;
Comparator<Product> byPrice = Comparator.comparingDouble(Product::price);
Comparator<Product> byName = Comparator.comparing(Product::name);
Comparator<Product> byStock = Comparator.comparingInt(Product::stock);
products.sort(byPrice);
System.out.println(products); // sorted by price ascending
products.sort(byName);
System.out.println(products); // sorted alphabeticallyreversed()
reversed() меняет порядок любого компаратора на обратный.
import java.util.Comparator;
Comparator<Product> mostExpensiveFirst =
Comparator.comparingDouble(Product::price).reversed();
products.sort(mostExpensiveFirst);
System.out.println(products);
// [Laptop($999.0), Mouse($29.99), USB Hub($24.99)]naturalOrder и reverseOrder
Comparator.naturalOrder() использует естественный порядок класса. reverseOrder() меняет его на обратный.
List<String> names = new ArrayList<>(List.of("Charlie", "Alice", "Bob"));
names.sort(Comparator.naturalOrder());
System.out.println(names); // [Alice, Bob, Charlie]
names.sort(Comparator.reverseOrder());
System.out.println(names); // [Charlie, Bob, Alice]
// Sort integers descending
List<Integer> nums = new ArrayList<>(List.of(5, 2, 8, 1, 9));
nums.sort(Comparator.reverseOrder());
System.out.println(nums); // [9, 8, 5, 2, 1]Компараторы с безопасной обработкой пустых значений
Comparator.nullsFirst() и nullsLast() обрабатывают пустые элементы без NPE.
import java.util.*;
List<String> withNulls = new ArrayList<>(Arrays.asList("Charlie", null, "Alice", null, "Bob"));
withNulls.sort(Comparator.nullsLast(Comparator.naturalOrder()));
System.out.println(withNulls); // [Alice, Bob, Charlie, null, null]
withNulls.sort(Comparator.nullsFirst(Comparator.naturalOrder()));
System.out.println(withNulls); // [null, null, Alice, Bob, Charlie]sorted() в потоке с Comparator
Используйте промежуточную операцию потока sorted() с Comparator для сортировки в функциональном стиле.
import java.util.stream.*;
record Employee(String name, String dept, double salary) {}
List<Employee> employees = List.of(
new Employee("Alice", "Engineering", 95000),
new Employee("Bob", "Marketing", 72000),
new Employee("Charlie", "Engineering", 105000)
);
// Sort by salary descending in a stream pipeline
employees.stream()
.sorted(Comparator.comparingDouble(Employee::salary).reversed())
.forEach(e -> System.out.println(e.name() + ": $" + e.salary()));
// Charlie: $105000.0 / Alice: $95000.0 / Bob: $72000.0Comparator: лямбда-выражение или ссылка на метод
Ссылки на методы делают Comparator ещё короче, если функция извлечения ключа является простым методом получения значения.
// Lambda
Comparator<String> c1 = (a, b) -> a.length() - b.length();
// Comparator.comparing with lambda
Comparator<String> c2 = Comparator.comparing(s -> s.length());
// Comparator.comparingInt with method reference (cleanest)
Comparator<String> c3 = Comparator.comparingInt(String::length);
List<String> words = new ArrayList<>(List.of("banana", "fig", "apple", "kiwi"));
words.sort(c3);
System.out.println(words); // [fig, kiwi, apple, banana]Состояние в Comparator
Хотя Comparator обычно должен быть не имеющим состояния, конфигурацию можно передать через параметры конструктора.
class DistanceComparator implements Comparator<String> {
private final String target;
DistanceComparator(String target) { this.target = target; }
@Override
public int compare(String a, String b) {
return Integer.compare(distance(a), distance(b));
}
private int distance(String s) { return Math.abs(s.length() - target.length()); }
}
List<String> words = new ArrayList<>(List.of("Java", "Go", "Python", "C", "Kotlin"));
words.sort(new DistanceComparator("Java"));
System.out.println(words); // closest length to "Java" firstПользовательская сортировка каталога товаров
Сортировка каталога товаров: сначала по доступности, затем по цене и названию.
import java.util.*;
record Item(String name, double price, boolean inStock) {}
List<Item> catalog = List.of(
new Item("Laptop", 999.0, true),
new Item("Case", 19.99, false),
new Item("Mouse", 29.99, true),
new Item("Monitor", 349.0, true)
);
Comparator<Item> catalogSort =
Comparator.comparing(Item::inStock).reversed() // in-stock first
.thenComparingDouble(Item::price) // then cheapest
.thenComparing(Item::name); // then alphabetical
catalog.stream().sorted(catalogSort)
.forEach(i -> System.out.printf("%s %-15s $%.2f%n",
i.inStock() ? "[Y]" : "[N]", i.name(), i.price()));Arrays.sort с Comparator
Arrays.sort(array, comparator) сортирует массивы объектов с помощью пользовательского Comparator.
String[] words = {"banana", "fig", "apple", "kiwi", "cherry"};
// Sort by length, then alphabetically for same length
Arrays.sort(words,
Comparator.comparingInt(String::length)
.thenComparing(Comparator.naturalOrder()));
System.out.println(Arrays.toString(words));
// [fig, kiwi, apple, banana, cherry]Быстрая проверка
Что создаёт Comparator.comparingDouble(Product::price).reversed()?
Итоги: Comparator и сортировка с помощью лямбда-выражений
Главные выводы:
- Comparator задаёт внешний порядок — используйте столько вариантов, сколько требуется
- Comparator.comparing(keyExtractor) создаёт Comparator на основе методов получения значений
- reversed() меняет порядок любого Comparator на обратный; naturalOrder()/reverseOrder() предназначены для типов с естественным порядком
- nullsFirst() и nullsLast() безопасно обрабатывают пустые элементы
- Используйте sorted(comparator) в потоковых конвейерах для сортировки в функциональном стиле
- Comparator можно передавать в sort(), Arrays.sort(), TreeSet и TreeMap
Часто задаваемые вопросы
Урок «Сортировка с Comparator и лямбда-выражениями» бесплатный?
Да — полный текст урока «Сортировка с Comparator и лямбда-выражениями» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Java Academy, подпишись на CoddyKit PRO. Курс Java Academy содержит 4 уроков всего.
Чему я научусь в уроке «Сортировка с Comparator и лямбда-выражениями»?
Создавайте экземпляры Comparator с помощью лямбда-выражений и фабричных методов Comparator.comparing. Ты практикуешь Java Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Java Academy?
Предыдущий опыт не требуется. Java Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 4.
Сколько времени занимает урок «Сортировка с Comparator и лямбда-выражениями»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Java Academy?
Да. Каждый урок Java Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Интерфейс Comparable
- Сортировка с Comparator и лямбда-выражениями
- Сортировка по нескольким ключам с thenComparing
- Сортировка массивов и коллекций на практике