Сортировка массива объектов по двум полям в Java

Пройдите тест, узнайте какой профессии подходите и получите бесплатную карьерную консультацию
В конце подарим скидку до 55% на обучение
Я предпочитаю
0%
Работать самостоятельно и не зависеть от других
Работать в команде и рассчитывать на помощь коллег
Организовывать и контролировать процесс работы

Быстрый ответ

Для эффективной сортировки списка в Java по двум свойствам можно использовать сочетание методов Comparator.comparing и thenComparing.

Java
Скопировать код
List<Person> people = // ... инициализация списка
people.sort(
        Comparator.comparing(Person::getLastName)
                  .thenComparing(Person::getFirstName)
);

В этом примере список people сортируется сначала по атрибуту lastName (фамилия), затем — по firstName (имя), используя ссылки на методы.

Пошаговое руководство по сортировке для начинающих

Властелин сортировки: Comparator

Чтобы отсортировать объекты по нескольким параметрам, вы можете создать собственный Comparator. Он позволяет сравнивать строки и числа с использованием метода compareTo.

Java
Скопировать код
// Поле для гольфа готово, отсортируем игроков по фамилии и возрасту!
Comparator<Person> peopleSorter = Comparator
    .comparing(Person::getLastName)
    .thenComparingInt(Person::getAge);

// Посмотрим, кто лучше играет.
Collections.sort(people, peopleSorter);

Java 8 и Streams: идеальное сочетание

В Java 8 API для потоков предусматривает возможность сортировки по двум полям.

Java
Скопировать код
// Гольферы, приветствуйте сортировку ваших данных по возрасту и фамилии!
List<Person> sortedPeople = people.stream()
    .sorted(Comparator.comparing(Person::getAge)
                      .thenComparing(Person::getLastName))
    .collect(Collectors.toList());

Регистрозависимость: важно ли это?

Для сортировки строк без учета регистра используйте String.compareToIgnoreCase().

Java
Скопировать код
Comparator<Person> caseInsensitiveComparator = Comparator
    .comparing(Person::getName, String.CASE_INSENSITIVE_ORDER)
    .thenComparingInt(Person::getAge);

// Независимо от того, как написаны имена — "Джон" или "джон"...
Collections.sort(people, caseInsensitiveComparator);

Для повторяющихся задач: реализация Comparable

Если вам часто приходится сортировать объекты Person по двум параметрам, стоит реализовать интерфейс Comparable.

Java
Скопировать код
public class Person implements Comparable<Person> {
    // поля, конструкторы, геттеры

    @Override
    public int compareTo(Person other) {
        int lastNameComparison = this.lastName.compareTo(other.lastName);
        return lastNameComparison != 0 ? lastNameComparison : Integer.compare(this.age, other.age);
        // Если фамилии одинаковые, сортируем по возрасту.
    }
}

// Gandalf, ваши "подчиненные" готовы к работе...
Collections.sort(people); // вмешательство compareTo.

Визуализация

Допустим, нам нужно отсортировать колоду карт сначала по номиналу карты, затем по масти:

Markdown
Скопировать код
Исходная колода: [♠2, ♥3, ♠3, ♥2, ♣2]

Итог двухэтапной сортировки:

Markdown
Скопировать код
Шаг 1:Сортировка по номиналу   Шаг 2: Сортировка по масти
[♠2, ♥2, ♣2, ♥3, ♠3]  ->  [♣2, ♥2, ♠2, ♥3, ♠3] // Масти отсортированы в соответствии с их кодами в Unicode.

Когда важна деталь: пользовательский Comparator

Если требуется особая сортировка для объекта Person, можно создать пользовательский компаратор:

Java
Скопировать код
Comparator<Person> customComparator = new Comparator<Person>() {
    @Override
    public int compare(Person p1, Person p2) {
        // Здесь может быть ваша своя логика сравнения.
    }
};

Collections.sort(people, customComparator); // Сортировка выполнена, приятного чаепития!

Производительность превыше всего: один Comparator для всего

Создайте единичный экземпляр Comparator для экономии ресурсов и улучшения повторного использования:

Java
Скопировать код
// Для тех, кто ценит производительность: общий Comparator в действии.
public class PersonComparators {
    public static final Comparator<Person> BY_NAME_AND_AGE = Comparator
        .comparing(Person::getName)
        .thenComparingInt(Person::getAge);
    
    // Закрытый конструктор для предотвращения создания экземпляров класса.
    private PersonComparators() {}
}

Collections.sort(people, PersonComparators.BY_NAME_AND_AGE); // Сортируем быстро и эффективно.

Золотое правило: Доверяй, но проверяй

Для эффективной сортировки лучше всего использовать встроенные инструменты Java, такие как Collections.sort и Comparator.

Полезные материалы

  1. Comparator (Java Platform SE 8) — официальная документация Oracle по Comparator в Java.
  2. Java – How to Use Comparator? — практическое руководство по работе с Comparator.
  3. Java 8 Stream sorted() Example — примеры сортировки потоков в Java 8 и их объяснения.
  4. Effective Java – Joshua Bloch – Google Книги — подробный анализ важности реализации Comparable.
  5. Java – How to Use Comparator? — продвинутое руководство по созданию пользовательских компараторов.