Arrays.sort() в Java: сортировка массива
Сортировка массива — это частая задача при написании Java-приложений. Статический метод Arrays.sort() из класса java.util.Arrays сортирует элементы массива по возрастанию «на месте» — быстро, без ручной реализации алгоритмов. В этом уроке разберём его перегрузки, сортировку по убыванию, сортировку строк и объектов, а также отличия от Collections.sort().
Базовый пример: сортировка по возрастанию
Метод Arrays.sort() позволяет отсортировать элементы массива по возрастанию:
import java.util.Arrays;
public class ArraysSortExample1 {
public static void main(String[] args) {
int[] array = new int[]{3, 1, 5, 6, 8};
Arrays.sort(array);
System.out.println(Arrays.toString(array));
}
}
Вывод программы:
[1, 3, 5, 6, 8] Важно
Arrays.sort() ничего не возвращает (тип void) и изменяет исходный массив. Если оригинальный порядок элементов ещё понадобится, сначала сделайте копию: int[] copy = Arrays.copyOf(array, array.length);
Перегрузки метода Arrays.sort()
В классе java.util.Arrays метод sort() перегружен для всех примитивных типов (кроме boolean) и для массивов объектов:
| Сигнатура | Что сортирует | Порядок |
|---|---|---|
sort(int[] a), sort(long[] a), sort(double[] a) и т.д. | Массив примитивов целиком | По возрастанию (естественный порядок) |
sort(int[] a, int fromIndex, int toIndex) | Диапазон массива примитивов | По возрастанию |
sort(Object[] a) | Массив объектов, реализующих Comparable | Естественный порядок (compareTo) |
sort(T[] a, Comparator<? super T> c) | Массив объектов по заданному правилу | Определяется компаратором (в том числе по убыванию) |
Под капотом
Для примитивов Arrays.sort() использует двухопорную быструю сортировку (Dual-Pivot Quicksort), для объектов — TimSort, стабильную модификацию сортировки слиянием. Средняя сложность в обоих случаях — O(n log n), поэтому писать пузырьковую сортировку вручную в рабочем коде не нужно.
Сортировка части массива
Перегрузка с параметрами fromIndex и toIndex сортирует только указанный диапазон. Начальный индекс включается, конечный — нет:
import java.util.Arrays;
public class ArraysSortRangeExample {
public static void main(String[] args) {
int[] array = {9, 7, 5, 3, 1};
Arrays.sort(array, 1, 4); // сортируем элементы с индексами 1, 2, 3
System.out.println(Arrays.toString(array)); // [9, 3, 5, 7, 1]
}
}
Если fromIndex > toIndex, будет выброшено IllegalArgumentException, а при выходе за границы массива — ArrayIndexOutOfBoundsException.
Сортировка по убыванию
Чтобы отсортировать массив по убыванию, используется перегрузка с компаратором Comparator.reverseOrder(). Она работает только с массивами объектов, поэтому вместо int[] нужен Integer[]:
import java.util.Arrays;
import java.util.Comparator;
public class ArraysSortDescExample {
public static void main(String[] args) {
Integer[] array = {3, 1, 5, 6, 8};
Arrays.sort(array, Comparator.reverseOrder());
System.out.println(Arrays.toString(array)); // [8, 6, 5, 3, 1]
}
}
Для массива примитивов int[] компаратор применить нельзя. Варианты решения:
- отсортировать по возрастанию и затем перевернуть массив циклом (поменять местами элементы с концов к середине);
- преобразовать через Stream API:
int[] desc = Arrays.stream(array).boxed().sorted(Comparator.reverseOrder()).mapToInt(Integer::intValue).toArray();
Так выглядит вариант с переворотом массива после сортировки:
int[] array = {3, 1, 5, 6, 8};
Arrays.sort(array); // [1, 3, 5, 6, 8]
for (int i = 0; i < array.length / 2; i++) {
int tmp = array[i];
array[i] = array[array.length - 1 - i];
array[array.length - 1 - i] = tmp;
}
System.out.println(Arrays.toString(array)); // [8, 6, 5, 3, 1]
Сортировка строк и объектов
Массив строк сортируется так же, как массив чисел: String реализует интерфейс Comparable, поэтому строки выстраиваются в лексикографическом порядке:
String[] names = {"Olga", "Anna", "Boris"};
Arrays.sort(names);
System.out.println(Arrays.toString(names)); // [Anna, Boris, Olga]
Для собственных классов есть два пути: реализовать Comparable в самом классе или передать Comparator вторым аргументом. Компаратор удобно строить через ссылки на методы:
import java.util.Arrays;
import java.util.Comparator;
record Person(String name, int age) {}
public class ArraysSortObjectsExample {
public static void main(String[] args) {
Person[] people = {
new Person("Olga", 30),
new Person("Anna", 25),
new Person("Boris", 35)
};
Arrays.sort(people, Comparator.comparingInt(Person::age));
System.out.println(Arrays.toString(people));
// [Person[name=Anna, age=25], Person[name=Olga, age=30], Person[name=Boris, age=35]]
}
}
Если элементы массива объектов не реализуют Comparable и компаратор не передан, во время выполнения будет выброшено ClassCastException.
Arrays.sort() и Collections.sort(): в чём разница
| Критерий | Arrays.sort() | Collections.sort() |
|---|---|---|
| Что сортирует | Массивы: примитивы и объекты | Списки (List), только объекты |
| Алгоритм | Dual-Pivot Quicksort (примитивы), TimSort (объекты) | TimSort |
| Стабильность | Стабильна для объектов, для примитивов неважна | Стабильна |
| Сортировка по убыванию | Через Comparator (только массивы объектов) | Через Comparator или Collections.reverseOrder() |
Начиная с Java 8 у списков есть и собственный метод list.sort(comparator) — Collections.sort() внутри делегирует именно ему.
Arrays.parallelSort()
С Java 8 доступен метод Arrays.parallelSort() с теми же перегрузками. Он разбивает массив на части, сортирует их в нескольких потоках через Fork/Join-пул и сливает результат. На больших массивах (сотни тысяч элементов и более) это даёт выигрыш на многоядерных процессорах; на маленьких массивах parallelSort() сам переключается на обычную последовательную сортировку, так что заметной разницы не будет.
int[] bigArray = new int[1_000_000];
// ... заполнение массива ...
Arrays.parallelSort(bigArray);
На чём чаще всего ошибаются
- Ожидают, что метод вернёт новый массив.
Arrays.sort()возвращаетvoidи сортирует на месте — записьint[] sorted = Arrays.sort(array);не скомпилируется. - Пытаются передать компаратор для
int[]. Перегрузка сComparatorсуществует только для массивов объектов — используйтеInteger[]или Stream API. - Печатают массив без
Arrays.toString().System.out.println(array)выведет что-то вроде[I@1b6d3586— хеш, а не содержимое. - Забывают про
null-элементы. При сортировке массива объектов сnullвнутри будетNullPointerException; обойти можно компараторомComparator.nullsFirst(...)илиComparator.nullsLast(...). - Сортируют перед
Arrays.binarySearch()не всегда. Бинарный поиск корректно работает только на отсортированном массиве — вызовArrays.sort()перед ним обязателен.
Часто задаваемые вопросы
Как отсортировать массив int[] по убыванию в Java?
Напрямую никак: перегрузка с Comparator работает только с объектами. Либо используйте Integer[] и Comparator.reverseOrder(), либо отсортируйте int[] по возрастанию и переверните его циклом, либо примените Stream API с boxed() и sorted(Comparator.reverseOrder()).
Какой алгоритм сортировки использует Arrays.sort()?
Для примитивных типов — двухопорную быструю сортировку (Dual-Pivot Quicksort), для массивов объектов — TimSort, стабильную модификацию сортировки слиянием. Средняя сложность обоих алгоритмов — O(n log n).
Чем Arrays.sort() отличается от Collections.sort()?
Arrays.sort() сортирует массивы, в том числе массивы примитивов, а Collections.sort() — списки (List) с объектами. Внутри Collections.sort() с Java 8 делегирует методу list.sort(), который также использует TimSort.
Возвращает ли Arrays.sort() новый массив?
Нет. Метод объявлен как void и изменяет переданный массив на месте. Если исходный порядок нужно сохранить, сначала создайте копию через Arrays.copyOf() и сортируйте её.
Видео объяснение
Предпочитаете видеоформат? Посмотрите этот урок с примерами и объяснениями.
Комментарии