
Java programátor expert
Java Collections Framework (JCF) patrí k najpoužívanejším API v Jave, pretože poskytuje kolekciu všestranne použiteľných dátových štruktúr. Pri programovaní pracujeme s dátami, ktoré si ukladáme do vhodných dátových štruktúr v pamäti a tie potrebujeme najčastejšie kategorizovať, spracovať, triediť, filtrovať, resp. transformovať na inú formu dát.
Na našom blogu venovali dátovým štruktúram. Ak si naše články čítal/a, určite vieš, že naprogramovať efektívnu, optimalizovanú, znovu-použiteľnú dátovú štruktúru nie je vôbec jednoduchá úloha. To je jeden z dôvodov, prečo využívame frameworky, teda akúsi formu knižníc, ktorá už obsahuje predprogramované sady komponentov ihneď použiteľné v projektoch a programátor sa tak môže venovať na projekte špecifickej biznis logike.
A aby sme si nemuseli všetko naprogramovať sami na zelenej lúke, vysokoúrovňový programovací jazyk ako je napr. Java ponúka programátorom kolekciu optimalizovaných, univerzálne použiteľných dátových kontajnerov, do ktorých si svoje dáta môžu uložiť.
Pod kolekciou rozumieme zbierku typovo podobných objektov zoskupených do jednej dátovej štruktúry a používame ju na ukladanie, načítavanie, manipuláciu a komunikáciu s agregovanými dátami. Príkladom môže byť zoznam zákazníkov, mailový priečinok s obdržanými správami alebo telefónny adresár mapujúci mená klientov na ich telefónne čísla.
V tomto článku si vysvetlíme, ako vznikol Java Collections Framework, čo obsahuje a prečo by sme sa mali ihneď začať učiť používať všetky jeho benefity.
Framework kolekcií navrhol a vyvinul predovšetkým Joshua Bloch a bol predstavený v Jave 2 (JDK 1.2) v roku 1998. Ak si čítal/-a jednu z najlepších kníh o Java – Effective Java 3rd Edition, Joshua ti určite nie je neznámy. Hlavnou motiváciou bolo priniesť ľahko rozšíriteľný, adaptovateľný, vysoko-výkonný framework, ktorý by obsahoval sadu základných kolekcií (ako dynamické polia, spájané zoznamy, stromové štruktúry, hashovacie tabuľky, atď) a ich implementácia by bola veľmi efektívna a optimalizovaná na výkon.
Pred týmto vydaním boli vývojári odkázaní na zoskupovanie objektov cez pole, triedy Vector a Hashtable, ktoré nebolo jednoduché rozšíriť a neimplementovali jednotné rozhranie. Programátori si tak väčšinovo programovali vlastné dátové štruktúry, alebo siahli po nejakej neštandardnej knižnici tretích strán.
Postupne sa JCF vyvíjal a získaval nové funkcie. V Jave 5 boli pridané generické triedy, ktoré zvýšili typovú bezpečnosť kolekcií. Neskôr, s príchodom Javy 8, boli kolekcie rozšírené o streamy, lambda výrazy a možnosť funkcionálneho programovania, čo ešte viac zjednodušilo prácu s dátovými štruktúrami. Toto boli doteraz dve najdôležitejšie aktualizácie tohto frameworku, avšak na JCF sa stále pracuje a každá aktualizácia JDK prináša do kolekcií menšie, či väčšie vylepšenia.
Framework kolekcií je zjednotená architektúra pre reprezentovanie a manipulovanie kolekcií. Skladá sa z troch častí: rozhrania, implementácie tried a algoritmy.
Rozhrania: Sú to abstraktné dátové typy (ADT), ktoré predstavujú kolekciu. Rozhrania umožňujú kolekciám, aby sa s nimi narábalo nezávisle od ich vnútornej reprezentácie. Sú dôležité, pretože umožňujú formovať hierarchiu tried.
Triedy: Tieto opakovateľne použiteľné štruktúry ponúkajú konkrétne implementácie rozhraní kolekcií.
Algoritmy: Výpočtové metódy na kolekciách ako sú napr. vyhľadávanie, triedenie alebo úpravu kolekcií.
Medzi najdôležitejšie rozhrania JCF, ktoré poskytujú všeobecnú štruktúru pre prácu s rôznymi typmi kolekcií, patria: Iterable, Collection, List, Queue, Set a Map.
Rozhranie Iterable je základné rozhranie v Jave, ktoré umožňuje iteráciu cez kolekciu objektov. Nachádza sa v balíku java.lang, je dostupné pre všetky kolekcie bez potreby importu. Kolekcie implementujúce Iterable môžu byť prechádzané pomocou cyklu for-each, ktoré výrazne zjednodušuje používanie. Rozhranie poskytuje jedinú metódu.
Metóda | Popis |
Iterator <E> iterator() | Vráti pre kolekciu iterator typu E. |
Nachádza sa v balíku java.util. Aby sme mohli využívať iterator na prechádzanie kolekcie potrebujeme preťažiť (override) a poskytnúť implementáciu pre nasledovné metódy.
Metóda | Popis |
boolean hasNext() | Vráti true, ak má iterácia viac prvkov. |
E next() | Vráti ďalší prvok E v iterácii |
void remove() | Odstráni posledný prvok vrátený iterátorom (voliteľná operácia). |
Základné rozhranie, ktoré predstavuje skupinu objektov. Je rodičom špecializovaných rozhraní, ako sú List, Set a Queue, pre ktoré definuje radu abstraktných metód (to znamená, že k dispozícii je iba signatúra metódy), ktoré podriadené kolekcie musia naimplementovať. Vďaka tomu je práca s kolekciami podobná a intuitívna. Nachádza sa v balíku java.util, podobne ako všetky podriadené kolekcie.
Metóda | Popis |
boolean add(E e) | Pridá zadaný prvok do kolekcie (voliteľná operácia). |
void clear() | Odstráni všetky prvky z tejto kolekcie (voliteľná operácia). |
boolean contains(Object o) | Vráti true, ak táto kolekcia obsahuje zadaný prvok. |
boolean equals(Object o) | Porovná zadaný objekt s touto kolekciou kvôli rovnosti. |
boolean isEmpty() | Vráti sa true, ak táto kolekcia neobsahuje žiadne prvky. |
Iterator<E> iterator() | Vráti iterátor nad prvkami v tejto kolekcii. |
boolean remove(Object o) | Odstráni jednu inštanciu zadaného prvku z tejto kolekcie, ak je prítomná (voliteľná operácia). |
int size() | Vráti počet prvkov v tejto kolekcii. |
Object[] toArray() | Vráti pole obsahujúce všetky prvky v tejto kolekcii. |
Definuje rozhranie pre kolekcie, kde záleží na poradí prvkov (tzv. ordered collections) a môžu obsahovať duplicitné elementy. Pri prístupe k prvkov sa využíva prístup na báze indexov, cez ktoré sa určuje ich pozícia v kolekcii.
Príklady implementácií tohto rozhrania sú kolekcie ArrayList, LinkedList, Vector, Stack.
Definuje rozhranie pre kolekcie, ktoré obsahujú množinu unikátnych prvkov bez duplicít. Elementy nie sú ukladané v žiadnom konkrétnom poradí (tzv. unordered collections). Avšak niektoré implementácie ako LinkedHashSet udržiava poradie vkladania prvkov. Vloženie jedného null elementu do tejto kolekcie Množina je povolené napr. u kolekcie HashSet, ale niektoré implementácie ako TreeSet vkladanie null prvkov neumožňujú.
Príklady implementácií tohto rozhrania sú kolekcie HashSet, TreeSet a LinkedHashSet.
Definuje rozhranie pre kolekcie, ktoré by mali byť spracované podľa FIFO (First In, First Out) princípu, aj keď niektoré varianty implementácie ako sú prioritné fronty sa nemusia tohto pridržiavať.
Príklady implementácií tohto rozhrania sú kolekcie LinkedList, PriorityQueue a ArrayDequeue.
Toto rozhranie patrí do JCF, ale nemá žiadny vzťah s rozhraním Collection, ktoré pracuje s jednou entitou, zatiaľ čo rozhranie Map pracuje s dvomi – unikátnym kľúčom a jeho príslušným objektom. Napr. kľúčom môže byť telefónne číslo a objektom majiteľ daného telefónu. Pre získanie objektu z kolekcie Mapa potrebujeme zvyčajne použiť jeho kľúč.
Príklady implementácií tohto rozhrania sú kolekcie HashMap, TreeMap a LinkedHashMap.
Rad by som ešte spomenul, že tento článok nespomína všetky kolekcie, ktoré nám Java Collections Framework ponúka a ak ti nejaká kolekcia pre tvoje špecifické zadanie alebo problém chýba, odporúčam pred vlastnou implementáciou kolekcie (čo je tiež možné riešenie) si pozrieť aktuálnu JCF dokumentáciu.
Za zmienku ešte stojí, že s príchodom JDK21 sa v JEP431 objavili tri nové rozhrania pre vytváranie sekvenčných kolekcií (SequencedCollection), sekvenčných množín (SequencedSet) a sekvenčných máp (SequencedMap).
JCF obsahuje aj množstvo algoritmov na manipuláciu s kolekciami. Tieto algoritmy sú implementované ako statické metódy v triede Collections. Medzi najdôležitejšie patria:
Zosumarizujme si ešte benefity, ktoré nám JCF ponúka:
Java Collections Framework nám ponúka obrovské množstvo rozhraní, tried a algoritmov na najrozličnejšie spektrum vývojárskych výziev, ktoré súvisia s efektívnou prácou s dátovými štruktúrami a dátami v Jave. Aj keď je náročné na začiatku zvládnuť jeho komplexnosť, investícia času do pochopenia JCF sa vývojárom z dlhodobého hľadiska len a len vyplatí.