Sortowanie według wielu kluczy za pomocą thenComparing
Łącz komparatory z thenComparing, aby sortować według wielu pól zgodnie z priorytetami.
Sortowanie według wielu kluczy za pomocą thenComparing to bezpłatna lekcja Java Academy na CoddyKit. To lekcja 3 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Java Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Java Academy zawiera 4 lekcji w sumie.
Sortowanie według wielu kluczy
thenComparing() łączy komparatory, aby sortować według wielu pól. Najpierw odbywa się sortowanie główne, następnie — w przypadku równości — pomocnicze itd.
Podstawowe użycie thenComparing
thenComparing() służy do rozstrzygania remisów po zastosowaniu głównego komparatora.
import java.util.*;
record Student(String name, int grade, double gpa) {}
List<Student> students = List.of(
new Student("Alice", 10, 3.9),
new Student("Bob", 11, 3.7),
new Student("Charlie", 10, 3.8),
new Student("Diana", 11, 3.7)
);
Comparator<Student> sort = Comparator.comparingInt(Student::grade)
.thenComparingDouble(Student::gpa).reversed()
.thenComparing(Student::name);
students.stream().sorted(sort).forEach(System.out::println);Sortowanie trzypoziomowe
Można łączyć dowolną liczbę poziomów thenComparing.
record Employee(String dept, String team, String name, double salary) {}
List<Employee> employees = List.of(
new Employee("Eng", "Backend", "Alice", 95000),
new Employee("Eng", "Backend", "Bob", 92000),
new Employee("Eng", "Frontend","Charlie", 88000),
new Employee("Mkt", "Growth", "Diana", 75000)
);
Comparator<Employee> sort = Comparator
.comparing(Employee::dept)
.thenComparing(Employee::team)
.thenComparing(Comparator.comparingDouble(Employee::salary).reversed());
employees.stream().sorted(sort)
.forEach(e -> System.out.printf("%s > %s > %s: $%.0f%n",
e.dept(), e.team(), e.name(), e.salary()));thenComparing z Comparator
Gdy dla kluczy pomocniczych potrzebny jest odwrócony lub niestandardowy porządek, należy użyć przeciążenia przyjmującego Comparator.
Comparator<Employee> sort = Comparator
.comparing(Employee::dept)
.thenComparing(Comparator.comparing(Employee::salary).reversed()); // highest paid first
// equivalent: .thenComparingDouble(Employee::salary, Comparator.reverseOrder())Sortowanie z polami null
Połączenie thenComparing z nullsLast/nullsFirst pozwala poprawnie obsługiwać opcjonalne pola.
record Product(String name, String category, Double rating) {}
Comparator<Product> sort = Comparator
.comparing(Product::category, Comparator.nullsLast(Comparator.naturalOrder()))
.thenComparing(Product::rating, Comparator.nullsLast(Comparator.reverseOrder()))
.thenComparing(Product::name);Dynamiczny wybór klucza sortowania
Klucz sortowania można wybrać w czasie działania programu na podstawie preferencji użytkownika.
static Comparator<Product> sortBy(String key) {
return switch (key) {
case "price" -> Comparator.comparingDouble(Product::price);
case "name" -> Comparator.comparing(Product::name);
case "stock" -> Comparator.comparingInt(Product::stock).reversed();
default -> Comparator.comparingDouble(Product::price);
};
}
String userChoice = "stock";
products.stream().sorted(sortBy(userChoice)).forEach(System.out::println);thenComparing z funkcją ekstrakcji
Przeciążenie thenComparing(Function<T,U>) wyodrębnia klucz Comparable na potrzeby sortowania pomocniczego, bez konieczności jawnego używania Comparator.
record Event(String type, int year, int month, int day) {}
Comparator<Event> chronological = Comparator
.comparing(Event::type)
.thenComparingInt(Event::year)
.thenComparingInt(Event::month)
.thenComparingInt(Event::day);Sortowanie kolekcji rekordów
Rekordy z metodami dostępowymi bezproblemowo współpracują z odwołaniami do metod w łańcuchach komparatorów.
record Order(String customerId, String status, double total, java.time.LocalDate date) {}
List<Order> orders = loadOrders();
Comparator<Order> byCustomerThenDate = Comparator
.comparing(Order::customerId)
.thenComparing(Order::date, Comparator.reverseOrder()); // newest first per customer
orders.stream().sorted(byCustomerThenDate)
.collect(Collectors.groupingBy(Order::customerId))
.forEach((cust, ords) -> {
System.out.println("Customer: " + cust);
ords.forEach(o -> System.out.println(" " + o.date() + " $" + o.total()));
});Gwarancja stabilnego sortowania
Metody List.sort() i Arrays.sort() dla obiektów w Javie używają stabilnego sortowania przez scalanie. Elementy uznane za równe podczas porównywania zachowują pierwotną kolejność względną.
// Stable sort example:
// First sort by name, then by dept
// Equal dept elements preserve the name order from previous sort
List<Employee> sorted = employees.stream()
.sorted(Comparator.comparing(Employee::name)) // 1st pass
.sorted(Comparator.comparing(Employee::dept)) // 2nd pass (stable!)
.collect(Collectors.toList());
// Within each dept, employees remain alphabetically sortedComparator.comparing z komparatorem klucza
Dwuargumentowa forma Comparator.comparing(keyExtractor, keyComparator) pozwala określić zarówno klucz, jak i jego porządek.
// Sort by name length, then alphabetically within same length
Comparator<String> c = Comparator
.comparing(String::length, Integer::compare)
.thenComparing(Comparator.naturalOrder());
List<String> words = new ArrayList<>(List.of("fig","apple","kiwi","banana","pea"));
words.sort(c);
System.out.println(words); // [fig, pea, kiwi, apple, banana]Przykład z życia: wyniki wyszukiwania lotów
Sortowanie wyników wyszukiwania lotów według ceny, następnie czasu trwania, a na końcu godziny wylotu.
record Flight(String airline, double price, int durationMin, java.time.LocalTime departs) {}
Comparator<Flight> bestFlight = Comparator
.comparingDouble(Flight::price)
.thenComparingInt(Flight::durationMin)
.thenComparing(Flight::departs);Zbieranie posortowanych wyników
Połącz sortowanie według wielu kluczy z kolektorami, aby tworzyć posortowane grupy lub mapy.
Map<String, List<Employee>> byDept = employees.stream()
.sorted(Comparator.comparing(Employee::dept)
.thenComparing(Comparator.comparingDouble(Employee::salary).reversed()))
.collect(Collectors.groupingBy(Employee::dept,
LinkedHashMap::new, // preserve insertion (sorted) order
Collectors.toList()));
byDept.forEach((dept, emps) -> {
System.out.println(dept + ":");
emps.forEach(e -> System.out.println(" " + e.name() + " $" + e.salary()));
});Szybki test
Sortowanie ma odbywać się najpierw według działu alfabetycznie, a następnie według wynagrodzenia malejąco. Który łańcuch jest poprawny?
Podsumowanie: sortowanie wielokryterialne z thenComparing
Najważniejsze informacje:
- thenComparing() dodaje pomocnicze klucze sortowania, stosowane, gdy główne klucze są równe
- Można łączyć dowolną liczbę poziomów thenComparing
- Użyj thenComparing(Comparator) wraz z reversed(), gdy pomocniczy klucz wymaga kolejności malejącej
- Połącz z nullsFirst/nullsLast dla opcjonalnych pól
- Metoda List.sort() w Javie jest stabilna — elementy równe zachowują pierwotną kolejność
- Dynamiczny wybór sortowania: użyj switch, aby w czasie działania zwrócić właściwy Comparator
Często zadawane pytania
Czy lekcja „Sortowanie według wielu kluczy za pomocą thenComparing” jest bezpłatna?
Tak — pełny tekst „Sortowanie według wielu kluczy za pomocą thenComparing” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Java Academy, przejdź na CoddyKit PRO. Kurs Java Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „Sortowanie według wielu kluczy za pomocą thenComparing”?
Łącz komparatory z thenComparing, aby sortować według wielu pól zgodnie z priorytetami. Ćwiczysz Java Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć Java Academy?
Nie wymagamy żadnego doświadczenia. Java Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 3 z 4.
Ile czasu zajmuje lekcja „Sortowanie według wielu kluczy za pomocą thenComparing”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji Java Academy?
Tak. Każda lekcja Java Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Interfejs Comparable
- Comparator i sortowanie za pomocą lambd
- Sortowanie według wielu kluczy za pomocą thenComparing
- Sortowanie tablic i kolekcji w praktyce