Интерфейс Collection в Java: методы и контракт - Вопросы
Всего: 6 вопросов
1. Что такое интерфейс Collection в Java и какие методы он объявляет?
Что такое интерфейс Collection в Java и какие методы он объявляет?
java.util.Collection<E> — корневой интерфейс ветки списков, множеств и очередей в Collection Framework. Он расширяет Iterable<E> и объявляет операции, общие для List, Set и Queue. Map интерфейс Collection не наследует.
Методы делятся на три группы:
- изменение коллекции:
add,remove,addAll,removeAll,retainAll,removeIf,clear; - проверки:
contains,containsAll,size,isEmpty; - перебор и преобразование:
iterator,toArray,stream,parallelStream,spliterator(иforEachизIterable).
Кроме того, в Collection заново объявлены equals() и hashCode(). Методов с индексом (например, get(int)) в Collection нет: у множеств и очередей нет позиций элементов, индексы есть только в List.
2. Что возвращают методы add(), addAll(), remove(), removeAll(), retainAll() и removeIf() интерфейса Collection?
Что возвращают методы add(), addAll(), remove(), removeAll(), retainAll() и removeIf() интерфейса Collection?
Все они возвращают boolean: true, если коллекция изменилась, и false, если осталась прежней. Если реализация отказывается выполнить операцию по другой причине, она бросает исключение, а не возвращает false.
add(e)—false, например, уSet, где такой элемент уже есть.addAll(c)—true, если добавлен хотя бы один элемент: дляHashSet, где часть элементов уже была, результат тожеtrue.remove(o)— удаляет только первое вхождение, равноеoпоequals().removeAll(c)— удаляет все элементы, которые есть вc, включая повторы; отсутствующие элементыcне мешают вернутьtrue.retainAll(c)— оставляет только элементы изc;true, если что-то удалено.removeIf(filter)— удаляет элементы, для которых условие истинно;true, если удалён хотя бы один.
3. Что такое необязательные операции Collection и почему List.of("a", "b").remove("z") бросает исключение, а Arrays.asList("a", "b").remove("z") возвращает false?
Что такое необязательные операции Collection и почему List.of("a", "b").remove("z") бросает исключение, а Arrays.asList("a", "b").remove("z") возвращает false?
Методы, которые меняют коллекцию (add, addAll, remove, removeAll, retainAll, removeIf, clear), в документации помечены как необязательные (optional operations). Реализация вправе их не поддерживать и бросать UnsupportedOperationException. Так устроены List.of(), Collections.unmodifiableCollection(), а для операций, меняющих размер, — Arrays.asList().
Если вызов ничего не изменил бы, необязательная операция может бросить исключение, но не обязана. Коллекции из List.of() отказывают сразу, не глядя на аргумент. Список Arrays.asList() сначала ищет элемент и бросает исключение, только когда действительно нужно удалить: remove("z") вернёт false, а remove("a") бросит UnsupportedOperationException.
Вывод для практики: по объявлению Collection<String> c нельзя понять, поддерживает ли объект add(). Если метод получил коллекцию извне и должен её менять, надёжнее работать с копией new ArrayList<>(c).
4. Какие есть способы получить массив из коллекции через toArray() и копирует ли он элементы?
Какие есть способы получить массив из коллекции через toArray() и копирует ли он элементы?
Вариантов три:
Object[] toArray()— возвращаетObject[]; привести его кString[]нельзя (ClassCastException), даже если внутри только строки;<T> T[] toArray(T[] a)— массив нужного типа, обычноtoArray(new String[0]);toArray(IntFunction<T[]> generator)(Java 11) — массив по ссылке на конструктор:toArray(String[]::new).
Если тип элементов не подходит под тип массива, два последних варианта бросают ArrayStoreException.
Массив всегда новый и не связан с коллекцией: присваивание array[0] = ... коллекцию не изменит. Но сами объекты не копируются — в массив попадают ссылки на те же объекты. Если в списке лежит new StringBuilder("a"), то после ((StringBuilder) list.toArray()[0]).append("!") список выведется как [a!].
5. Когда две коллекции в Java равны по equals()?
Когда две коллекции в Java равны по equals()?
Сам Collection правило равенства не задаёт — его уточняют подинтерфейсы:
- два
Listравны, если содержат равные элементы в том же порядке, независимо от класса:ArrayListс[1, 2, 3]равен такому жеLinkedList; - два
Setравны, если содержат одни и те же элементы:HashSetравенTreeSetс теми же элементами; - список никогда не равен множеству.
ArrayDeque, PriorityQueue и коллекция map.values() не являются ни List, ни Set и не переопределяют equals(), поэтому сравниваются по ссылке: две очереди с одинаковыми элементами не равны.
Хеш-код тоже зависит от подинтерфейса: у List он учитывает порядок элементов, у Set равен сумме хеш-кодов элементов. Сами элементы методы contains(), remove(), removeAll() ищут через equals(), поэтому в своих классах его нужно переопределять.
6. Как менялся интерфейс Collection по версиям Java и зачем в нём default-методы?
Как менялся интерфейс Collection по версиям Java и зачем в нём default-методы?
- Java 1.2 — интерфейс появился вместе с Collection Framework:
add,remove,contains,size,iterator,toArrayи другие. - Java 5 — стал обобщённым (
Collection<E>) и получил родителяIterable, отсюда цикл for-each. - Java 8 — default-методы
removeIf(),stream(),parallelStream(),spliterator();forEach()вIterable. - Java 11 — default-метод
toArray(IntFunction<T[]>). - Java 21 — подинтерфейс
SequencedCollection.
Default-методы имеют реализацию прямо в интерфейсе. Поэтому новые методы добавились в Collection, не сломав старые классы, которые его реализуют: им не пришлось ничего дописывать.