Тема 6 — Колекции (Collections Framework)
Преди Java 5.0 всеки контейнер работеше с Object референции — програмистът ръчно привеждаше типове и нямаше никаква гаранция при компилация. С добавянето на generics и autoboxing/unboxing Collections Framework се превърна в типобезопасна, изразителна алтернатива на STL, идваща от кутията. Тази глава разглежда основните интерфейси, начина им на ползване и механизма за обхождане.
Йерархия на интерфейсите и основните имплементации в Collections Framework. Collection и Map са двете независими йерархии.
1. Еволюция и мотивация
1.1 Ранни ограничения (преди Java 5.0)
Двата оригинални класа контейнери — Vector и Hashtable — имат два съществени недостатъка:
- Анонимни типове — работят с
Object; при извличане е задължително ръчно привеждане и се губи типова безопасност; - Без поддръжка на прости типове — задължително обгръщане в wrapper класове с произтичащ режиен разход.
1.2 Collections Framework
Рамка, добавена за разширяване на оригиналните класове:
- Нови интерфейсни абстракции;
- Множество нови имплементации;
- Алгоритми (в
java.util.Collections); - Реализация на STL концепции в Java.
Пакет: java.util.
1.3 Две основни йерархии
Collection— контейнер, съхраняващ обекти (елементи);Map— двойки ключ/стойност; не наследяваCollection.
1.4 Начин на реализация
Основата е upcasting към интерфейс:
- При запис типът се преобразува нагоре по йерархията;
- При извличане без generics е нужно downcasting;
- С generics компилаторът гарантира коректността — грешките са при компилация, не при изпълнение.
2. Интерфейс Collection
Дефинира абстракция за съхранение — не определя начин на организация (дали е наредена, дали допуска дублиране и т.н.).
2.1 Основни методи
boolean add(E element) // добавя; false при дублиране (Set); UnsupportedOperationException за readonlyboolean remove(Object element) // премахваboolean contains(Object element) // true ако се съдържаint size() // брой елементиboolean isEmpty() // true ако е празнаIterator<E> iterator() // обект за обхождане
// Групови операции:boolean addAll(Collection<? extends E> c)boolean removeAll(Collection<?> c)boolean containsAll(Collection<?> c)3. Параметризирани колекции (Generics)
// С generics — типова безопасност:Collection<Date> dates = new ArrayList<Date>();dates.add(new Date()); // OKdates.add("foo"); // компилационна грешка
// Без generics — unchecked warning:Collection dates = new ArrayList();dates.add(new Date()); // позволено, но опасноArrayList<String> и ArrayList<Date> са различни типове — присвояването между тях е компилационна грешка.
4. Преобразуване между масиви и колекции
Колекция → масив:
List<String> list = ...;String[] arr = list.toArray(new String[0]); // предпочитаният вариантObject[] raw = list.toArray(); // без type safetyМасив → колекция:
String[] myStrings = {"a", "b", "c"};List<String> list = Arrays.asList(myStrings); // фиксиран размер — add/remove хвърля UnsupportedOperationExceptionArrays съдържа и помощни методи за сортиране, търсене и сравняване на масиви.
5. Итератор (Iterator)
Iterator<E> е стандартизираният механизъм за обхождане, разделящ логиката на достъп от структурата на колекцията:
interface Iterator<E> { boolean hasNext(); // true ако има следващ елемент E next(); // следващ елемент (NoSuchElementException ако няма) void remove(); // премахва последния върнат от next() елемент}Типично ползване:
public void printAll(Collection<String> c) { Iterator<String> it = c.iterator(); while (it.hasNext()) { System.out.println(it.next()); }}Изключения при remove():
UnsupportedOperationException— при колекция само за четене;IllegalStateException— приremove()без предшестващnext()или два пъти подред.
5.1 for-each за колекции (Java 5.0+)
Синтактично удобство над Iterator — компилаторът го разгъва до iterator() + while:
Collection<Date> collection = ...;for (Date date : collection) { System.out.println(date);}Налично за всеки тип, имплементиращ Iterable<E>. Не е приложимо директно за Map (двусмислено — ключ или стойност).
6. Типове колекции
6.1 Интерфейс Set
- Не допуска дублиране на елементите;
- Проверката е базирана на
equals()(иhashCode()за хеширани имплементации); add()с вече съществуващ елемент връщаfalseбез хвърляне на изключение.
6.2 Интерфейс SortedSet
Разширява Set с управление на подредба — елементите са наредени по compareTo() или зададен Comparator:
SortedSet<E> subSet(E from, E to) // подмножество [from, to)SortedSet<E> headSet(E to) // елементи < toSortedSet<E> tailSet(E from) // елементи >= fromE first() // минимален елементE last() // максимален елементComparator<? super E> comparator() // null ако естествена подредба6.3 Интерфейс List
Линейна наредена колекция с позиционен достъп:
void add(E element) // добавя в краяvoid add(int index, E element) // вмъква на позиция; изместване надясноvoid remove(int index) // премахва на позицияE get(int index) // получаване; IndexOutOfBoundsException при невалиден индексObject set(int index, E element) // замяна; връща стария елемент6.4 Интерфейс Map
Съхранява уникални ключ/стойност двойки. Не наследява Collection. Основна йерархия: Map → SortedMap.
V put(K key, V value) // добавя/замества; връща старата стойностV get(Object key) // стойност по ключboolean containsKey(Object key)Set<K> keySet() // множеството на ключоветеCollection<V> values() // колекция от стойноститеSet<Map.Entry<K,V>> entrySet() // двойките за обхожданеРезюме
- Collections Framework предоставя унифицирана рамка от интерфейси и класове, еквивалентни на STL в Java.
- Две основни йерархии:
Collection(елементи) иMap(ключ/стойност двойки) —Mapне еCollection. - С Generics (Java 5.0+) колекциите получават типова безопасност при компилация; autoboxing позволява прозрачна работа с прости типове.
Iteratorе стандартизираният механизъм за обхождане;for-eachе синтактично удобство над него.Setзабранява дублирания;Listподдържа ред и позиционен достъп;SortedSetдобавя управление на подредбата.