Collections.sort: примеры (JAVA)
Collections.sort(List list): void Описание Collections.sort в Java
Метод Collections.sort служит для упорядочивания элементов списка в Java. Он изменяет переданный список на месте и не возвращает значение (тип возвращаемого значения - void). Метод имеет две перегрузки:
Collections.sort(List<T> list)- выполняет сортировку в естественном порядке элементов. Элементы должны реализовывать интерфейсComparable<T>.Collections.sort(List<T> list, Comparator<? super T> c)- выполняет сортировку с использованием переданного компаратораComparator. Если компаратор равенnull, используется естественный порядок элементов.
Ключевые свойства и поведение:
- Сортировка производится "вместо" - список изменяется на месте; возвращаемого значения нет.
- Алгоритм сортировки для объектов является стабильным и адаптивным (в современных реализациях используется TimSort для массивов объектов и похожие стратегии), сложность в худшем случае O(n log n), при благоприятных входных данных возможны оптимизации.
- Если список равен
null, генерируетсяNullPointerException. - Если элементы не взаимно сравнимы и используется естественный порядок, генерируется
ClassCastException. - Если список не поддерживает операции модификации (например, не изменяемый список), генерируется
UnsupportedOperationException. - Метод не синхронизирован. При доступе из нескольких потоков требуется внешняя синхронизация или использование потокобезопасных структур.
Примеры использования Collections.sort
Несколько компактных примеров с кодом и результатом.
Сортировка списка Integer по возрастанию
import java.util.*;
List<Integer> list = new ArrayList<>(Arrays.asList(5, 1, 3, 2));
Collections.sort(list);
System.out.println(list);
[1, 2, 3, 5]
Сортировка строк по длине с компаратором
import java.util.*;
List<String> names = new ArrayList<>(Arrays.asList("Ivan", "A", "Alex"));
Collections.sort(names, Comparator.comparingInt(String::length));
System.out.println(names);
[A, Ivan, Alex]
Обратный порядок через компаратор
import java.util.*;
List<Integer> nums = new ArrayList<>(Arrays.asList(2, 9, 4));
Collections.sort(nums, Comparator.reverseOrder());
System.out.println(nums);
[9, 4, 2]
Сортировка пользовательского класса, реализующего Comparable
import java.util.*;
class Person implements Comparable<Person> {
String name; int age;
Person(String n, int a){ name=n; age=a; }
public int compareTo(Person o){ return Integer.compare(age, o.age); }
public String toString(){ return name+":"+age; }
}
List<Person> ppl = new ArrayList<>(Arrays.asList(new Person("M",30), new Person("J",25)));
Collections.sort(ppl);
System.out.println(ppl);
[J:25, M:30]
Альтернативы в Java и отличия
Похожие варианты в стандартной библиотеке и их особенности:
List.sort(Comparator<? super E> c)- метод интерфейса List, доступен с Java 8. Предпочтителен при наличии экземпляра списка, так как выполняет ту же операцию напрямую; удобен для цепочек вызовов.Arrays.sort(…)- для массивов. При работе с примитивными массивами это более эффективный выбор; для объектов использует схожий алгоритм сортировки.Stream.sorted()- возвращает отсортированный поток без изменения исходной коллекции; полезно для функционального стиля и последующей агрегации.
Когда что выбирать:
- Для сортировки существующего списка предпочтительнее
list.sortилиCollections.sort(эквивалентное поведение в большинстве реализаций). - Для массивов -
Arrays.sort. - Если нужно получить новый отсортированный набор, не изменяя оригинал, удобно
stream().sorted()или создание копии списка и её сортировка.
Аналоги в других языках и отличия
Ниже краткие соответствия с примерами кода и результатами.
JavaScript (Array.prototype.sort)
const arr = [3,1,10];
arr.sort((a,b) => a - b);
console.log(arr);
[1,3,10]
Отличие: сортировка по умолчанию приводит элементы к строкам; для чисел нужен компаратор.
Python (list.sort и sorted)
a = [3,1,2]
a.sort()
print(a)
b = [3,1,2]
c = sorted(b)
print(c)
[1,2,3] [1,2,3]
Отличие: list.sort изменяет список на месте; sorted возвращает новый список.
PHP (sort, usort)
$a = [3,1,2];
sort($a);
print_r($a);
$b = ["a"=>2,"b"=>1];
uksort($b, function($x,$y){ return $x <=> $y; });
print_r($b);
Array ( [0] => 1 [1] => 2 [2] => 3 ) Array ( [b] => 1 [a] => 2 )
C# (List<T>.Sort и Array.Sort)
var list = new List<int>{3,1,2};
list.Sort();
Console.WriteLine(String.Join(",", list));
1,2,3
Отличие: сигнатуры и поведение схожи с Java.
Go (sort package)
import ("fmt"; "sort")
arr := []int{3,1,2}
sort.Ints(arr)
fmt.Println(arr)
[1 2 3]
SQL (ORDER BY)
SELECT name FROM users ORDER BY age ASC;
-- Результат: строки из таблицы users отсортированы по age
Kotlin
val list = mutableListOf(3,1,2)
list.sort()
println(list)
val newList = list.sorted() // возвращает новый список
[1, 2, 3] [1, 2, 3]
Lua (table.sort)
t = {3,1,2}
table.sort(t)
for i,v in ipairs(t) do print(v) end
1 2 3
Короткие замечания: реализации в других языках часто возвращают новый массив/список или изменяют на месте; в динамических языках сравнение по умолчанию может отличаться и требовать явного компаратора для корректной сортировки чисел или сложных объектов.
Типичные ошибки при использовании Collections.sort
Несколько распространённых ошибок с примерами и результатами.
NullPointerException при null-ссылке на список
List<Integer> list = null;
Collections.sort(list);
Exception in thread "main" java.lang.NullPointerException
at java.util.Objects.requireNonNull(Objects.java:...) ...
ClassCastException при несовместимых типах без компаратора
List list = Arrays.asList(1, "two", 3);
Collections.sort(list);
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String ...
UnsupportedOperationException при попытке сортировать не модифицируемый список
List<Integer> fixed = Collections.unmodifiableList(new ArrayList<>(Arrays.asList(3,1)));
Collections.sort(fixed);
Exception in thread "main" java.lang.UnsupportedOperationException
ConcurrentModificationException при одновременной итерации и сортировке
List<Integer> list = new ArrayList<>(Arrays.asList(3,1,2));
Iterator<Integer> it = list.iterator();
Collections.sort(list);
it.next(); // итератор обнаруживает изменение коллекции
Exception in thread "main" java.util.ConcurrentModificationException
NullPointerException при наличии null-элементов без обработки
List<String> list = new ArrayList<>(Arrays.asList("a", null, "b"));
Collections.sort(list);
Exception in thread "main" java.lang.NullPointerException
at java.lang.String.compareTo(String.java:...)
Решение: использовать Comparator.nullsFirst или nullsLast при необходимости избежать NPE.
Изменения в реализации и API
Ключевые эволюционные моменты:
- В Java 7 и выше для сортировки массивов объектов применяется TimSort - стабильный адаптивный алгоритм, который улучшает производительность на почти отсортированных входных данных.
- В Java 8 в интерфейс List добавлен метод
sort(Comparator<? super E> c). В современных реализацияхCollections.sortделегирует вызов внутренней реализации списка, поэтому поведение выравнивается. - С течением версий уделяется внимание стабильности и оптимизациям для частично отсортированных данных; публичный контракт остаётся прежним.
Расширенные и нетривиальные примеры применения
Подробные примеры с пояснениями и результатами.
Сортировка по нескольким полям с использованием Comparator
import java.util.*;
record Person(String name, int age, double salary){}
List<Person> ppl = new ArrayList<>(List.of(
new Person("A", 30, 5000),
new Person("B", 25, 6000),
new Person("C", 30, 4000)
));
Collections.sort(ppl, Comparator.comparing(Person::age)
.thenComparing(Comparator.comparing(Person::salary).reversed()));
System.out.println(ppl);
[B, C, A] -- Пояснение: сначала по age, затем по убыванию salary при равных возрастах.
Сортировка с учетом null-значений
import java.util.*;
List<String> items = new ArrayList<>(Arrays.asList("b", null, "a"));
Collections.sort(items, Comparator.nullsFirst(String::compareTo));
System.out.println(items);
[null, a, b]
Стабильность сортировки: демонстрация сохранения порядка равных элементов
import java.util.*;
class Item { int key; String source; Item(int k, String s){key=k; source=s;} public String toString(){return key+":"+source;} }
List<Item> list = new ArrayList<>();
list.add(new Item(1,"first"));
list.add(new Item(1,"second"));
Collections.sort(list, Comparator.comparingInt(i -> i.key));
System.out.println(list);
[1:first, 1:second] -- Пояснение: порядок элементов с одинаковым ключом сохраняется.
Сортировка подсписка (subList) без копирования
import java.util.*;
List<Integer> list = new ArrayList<>(Arrays.asList(5,4,3,2,1));
List<Integer> sub = list.subList(1,4); // элементы с индексами 1..3
Collections.sort(sub); // влияет на исходный list
System.out.println(list);
System.out.println(sub);
[5, 2, 3, 4, 1] [2, 3, 4] -- Пояснение: subList представляет часть оригинального списка, сортировка sub отражается в основном списке.
Сортировка с использованием Collator для локализованных строк
import java.text.Collator;
import java.util.*;
List<String> words = new ArrayList<>(Arrays.asList("ё", "е", "я", "a"));
Collator coll = Collator.getInstance(new java.util.Locale("ru"));
Collections.sort(words, coll);
System.out.println(words);
[a, е, ё, я] -- Пояснение: Collator учитывает правила конкретного языка при сравнении строк.
Использование Stream.sorted для получения нового списка (альтернатива без изменения оригинала)
import java.util.*;
import java.util.stream.Collectors;
List<Integer> orig = List.of(3,1,2);
List<Integer> sorted = orig.stream().sorted().collect(Collectors.toList());
System.out.println(orig);
System.out.println(sorted);
[3, 1, 2] [1, 2, 3] -- Пояснение: оригинал остаётся неизменным.
Производительность: сортировка LinkedList против ArrayList
Для LinkedList операции доступа по индексу дорогостоящие. Вызов Collections.sort на LinkedList может быть менее эффективен, чем на ArrayList, так как алгоритм может выполнять множество обращений по индексам. Рекомендуется преобразовывать в ArrayList при необходимости высокой производительности.
List<Integer> linked = new LinkedList<>(Arrays.asList(5,4,3,2,1));
List<Integer> temp = new ArrayList<>(linked);
Collections.sort(temp);
System.out.println(temp);
[1, 2, 3, 4, 5]