Класс Collections в Java: методы и примеры - Вопросы

Всего: 7 вопросов

1. 

Что такое класс Collections в Java и какие методы в нём есть?

java.util.Collections — служебный (utility) класс Collection Framework, состоящий только из статических методов. Конструктор у него закрытый, объект создать нельзя, методы вызываются через имя класса: Collections.sort(list). Не путайте его с интерфейсом Collection.

Методы делятся на три группы:

  • алгоритмы над списком: sort(), binarySearch(), reverse(), shuffle(), swap(), fill(), copy(), rotate();
  • вычисления над любой коллекцией: max(), min(), frequency(), disjoint();
  • фабрики списков и обёрток: nCopies(), addAll(), emptyList(), singletonList(), unmodifiableList(), synchronizedList(), checkedList().

Методы, которые переставляют элементы, меняют список через set(), поэтому работают с ArrayList, LinkedList и Arrays.asList(). Списки из List.of(), nCopies() и unmodifiableList() на перестановку отвечают UnsupportedOperationException — сначала сделайте копию: new ArrayList<>(List.of(...)). Для массивов есть аналогичный класс Arrays.

2. 

Почему Collections.binarySearch() работает только с отсортированным списком и что он возвращает?

Бинарный поиск на каждом шаге сравнивает ключ со средним элементом и отбрасывает половину списка — это корректно, только если список отсортирован. Метод возвращает индекс найденного элемента, а если элемента нет — -(точка вставки) - 1, где точка вставки — позиция, на которой элемент стоял бы в отсортированном списке. Обратно её получают так: -result - 1. Для ArrayList поиск занимает O(log n).

List<String> list = Arrays.asList("красный", "синий", "зеленый");
System.out.println(Collections.binarySearch(list, "зеленый")); // -1, хотя indexOf = 2
Collections.sort(list);                                        // [зеленый, красный, синий]
System.out.println(Collections.binarySearch(list, "красный")); // 1
System.out.println(Collections.binarySearch(list, "черный"));  // -4

Java не проверяет, отсортирован ли список, поэтому исключения не будет — только неверный результат. Если список отсортирован компаратором, например Collections.reverseOrder(), искать нужно с тем же компаратором: Collections.binarySearch(list, key, Collections.reverseOrder()).

3. 

Как перемешать, перевернуть список и поменять местами элементы методами shuffle(), reverse() и swap()?

Все три метода изменяют сам список и ничего не возвращают: Collections.reverse(list) переворачивает порядок элементов, Collections.swap(list, i, j) меняет местами элементы с индексами i и j, Collections.shuffle(list) переставляет элементы в случайном порядке.

List<String> list = Arrays.asList("красный", "синий", "зеленый", "черный");
Collections.reverse(list);   // [черный, зеленый, синий, красный]
Collections.swap(list, 0, 3); // [красный, зеленый, синий, черный]
Collections.shuffle(list);   // при каждом запуске свой порядок

Чтобы перемешивание повторялось от запуска к запуску (тесты, воспроизведение бага), передайте генератор с фиксированным начальным значением: Collections.shuffle(list, new Random(42)). Индекс вне [0, size()) в swap() даёт IndexOutOfBoundsException. Чтобы перевернуть список, не меняя исходный, сначала сделайте копию: new ArrayList<>(list).

4. 

Чем отличаются методы Collections.fill() и Collections.nCopies()?

Collections.fill(list, obj) заменяет каждый существующий элемент списка на obj и не меняет размер: пустой список после fill() останется пустым. Collections.nCopies(n, obj) создаёт новый неизменяемый список из n одинаковых элементов; чтобы его изменять, копируют в ArrayList:

List<String> filled = new ArrayList<>(Collections.nCopies(3, "черный"));
filled.add("белый"); // [черный, черный, черный, белый]

Без копии add() бросит UnsupportedOperationException, а nCopies(-1, "x") — IllegalArgumentException. Все позиции nCopies() ссылаются на один объект: после Collections.nCopies(3, new StringBuilder()) и get(0).append("x") список выводится как [x, x, x].

5. 

Как посчитать вхождения элемента и проверить, есть ли у коллекций общие элементы: frequency() и disjoint()?

Collections.frequency(collection, obj) возвращает, сколько раз элемент встречается в коллекции, сравнивая через equals(); obj = null допустим. Collections.disjoint(c1, c2) возвращает true, если общих элементов нет (для двух пустых коллекций — тоже true). Оба метода принимают любую Collection.

List<String> colors = Arrays.asList("красный", "синий", "красный", null);
Collections.frequency(colors, "красный");                    // 2
Collections.frequency(colors, "Красный");                    // 0: equals() учитывает регистр
Collections.frequency(colors, null);                         // 1
Collections.disjoint(colors, List.of("красный", "оранжевый")); // false

Для собственных классов frequency() считает правильно, только если переопределён equals(). Самый частый элемент находят комбинацией: Collections.max(list, Comparator.comparingInt(x -> Collections.frequency(list, x))), но это O(n²) — для больших данных частоты считают за один проход в HashMap.

6. 

Для чего нужны методы Collections.addAll(), emptyList() и singletonList()?

Collections.addAll(collection, e1, e2, ...) добавляет перечисленные элементы в существующую коллекцию и возвращает true, если она изменилась. Для Set, где все элементы уже были, вернётся false; для списка из Arrays.asList() — UnsupportedOperationException.

emptyList() и singletonList(obj) возвращают неизменяемые списки из нуля и одного элемента; add() на них бросает UnsupportedOperationException. Их возвращают из методов, чтобы не создавать лишний ArrayList: emptyList() каждый раз отдаёт один и тот же общий объект. Если вызывающий код должен наполнять результат, возвращайте new ArrayList<>().

С Java 9 вместо них часто пишут List.of() и List.of(obj). Разница: singletonList(null) допустим и даёт [null], а List.of(null) бросает NullPointerException.

7. 

Какие ошибки чаще всего допускают при работе с классом Collections?

  • binarySearch() на неотсортированном списке или с другим компаратором: исключения нет, результат просто неверный (например, -1 для существующего элемента).
  • sort(), shuffle(), reverse() на списке из List.of(), nCopies() или unmodifiableList() — UnsupportedOperationException; addAll() на Arrays.asList() — тоже.
  • copy(dest, src) в new ArrayList<>(10): важна не ёмкость, а size(), равный 0, поэтому IndexOutOfBoundsException: Source does not fit in dest. Независимую копию делают через new ArrayList<>(src).
  • max() и min() на пустой коллекции — NoSuchElementException; проверьте isEmpty() или используйте stream().max(cmp), который возвращает Optional. Строки сравниваются по кодам символов, поэтому Collections.max(Arrays.asList("кот", "собака", "ёж")) вернёт "ёж".
  • fill() на пустом списке ничего не добавляет, а nCopies() с изменяемым объектом хранит одну и ту же ссылку во всех позициях.
  • frequency() для класса без переопределённого equals() сравнивает ссылки и не находит равные по содержимому объекты.

Сдвиг в rotate() ошибкой не бывает: отрицательный сдвигает влево, а значение больше размера берётся по модулю (rotate(list, 7) для пяти элементов — то же, что rotate(list, 2)).

Страница 1 из 1