Image
22.6.2016 0 Comments

Java pod lupou I. /13.časť

Späť na úvod >> Späť na programovanie >> Späť na seriál

Balík java.util

V ďalšej časti seriálu sa pozrieme, čo ponúka Java v balíku java.util. Ako naznačuje jeho názov, balík java.util obsahuje zbierku rozličných užitočných tried, prevažne údajových štruktúr.

Údajové štruktúry

Podstatnú časť balíka java.util tvoria triedy a rozhrania tzv. kolekčného rámca (collection framework). Základom tohto rámca je šestica rozhraní Collection, List, Set, SortedSet, Map a SortedMap.

Rozhrania kolekčného rámca

Rozhranie Collection reprezentuje všeobecný pojem kolekcie (zbierky) údajov. Kolekciou rozumieme ľubovoľnú skupinu údajov, usporiadanú či neusporiadanú. Jednotlivé údaje nazveme prvkami danej kolekcie. Kolekcia môže i nemusí dovoľovať duplicitu prvkov. Java neposkytuje žiadne triedy, ktoré by priamo implementovali rozhranie Collection.

Rozhranie Collection obsahuje nasledujúce metódy: size() vracia počet prvkov v kolekcii, isEmpty() zisťuje, či je kolekcia prázdna, contains() testuje prítomnosť objektu v kolekcii, iterator() vracia iterátor (pozri ďalej) pre prístup k prvkom kolekcie, toArray() prevádza kolekciu na pole objektov, add()/remove() pridáva/odoberá prvok do/z kolekcie, containsAll() testuje prítomnosť všetkých prvkov kolekcie v inej kolekcii, addAll()/removeAll() pridáva/odoberá všetky prvky kolekcie do/z inej kolekcie, retainAll() odoberá z kolekcie všetky prvky, ktoré sa nenachádzajú v inej kolekcii, a clear() odstraňuje všetky prvky z kolekcie.

Rozhranie Collection má niekoľko potomkov. Prvým z nich je rozhranie List, ktoré reprezentuje zoznam – usporiadanú postupnosť údajov. Každý prvok zoznamu má priradený celočíselný index (číslovanie sa začína od nuly). Rozhranie List pridáva niekoľko nových metód: get() vracia prvok na určenej pozícii, set() nahrádza prvok na určenej pozícii novým prvkom, add() vkladá nový prvok do zoznamu na určenú pozíciu, remove() odoberá zo zoznamu prvok na určenej pozícii, indexOf()/lastIndexOf() vracia index prvého/posledného výskytu zadaného prvku v zozname, listIterator() vracia špeciálny iterátor pre zoznamy a subList() vracia podzoznam zoznamu.

Druhý potomok rozhrania Collection má názov Set a predstavuje matematický pojem množiny – neusporiadané kolekcie údajov bez duplicitných prvkov. Rozhranie Set nezavádza žiadne nové metódy. Má však potomka, rozhranie SortedSet, ktoré reprezentuje usporiadanú množinu. Takáto množina má svoje prvky usporiadané buď „prirodzeným“ spôsobom, alebo na základe objektu implementujúceho rozhranie Comparator, obsahujúce dve metódy, compare() a equals(), ktoré vhodným spôsobom definujú reláciu úplného (sic!) usporiadania.

V rozhraní SortedSet nájdeme zopár nových metód: comparator() vracia príslušný objekt Comparator, subSet() vracia vybranú podmnožinu danej množiny, headSet() vracia všetky prvky „menšie“ ako zadaný prvok, tailSet() vracia všetky prvky „väčšie alebo rovné“ ako zadaný prvok a first()/last() vracia „najmenší/najväčší“ prvok množiny.

Piate údajové rozhranie Map (nie je potomkom rozhrania Collection) predstavuje mapu – objekt, ktorý realizuje transformáciu zadaného kľúča na hodnotu. Mapa teda obsahuje množinu dvojíc kľúč–hodnota. Usporiadanie mapy je v zásade určené usporiadaním týchto dvojíc (presnejšie poradím, v akom sú tieto dvojice sprístupňované iterátormi).

Rozhranie Map obsahuje niekoľko metód významovo zhodných s metódami rozhrania Collection, menovite size(), isEmpty(), clear(), a ďalej vlastné špecifické metódy: containsKey() testuje prítomnosť zadaného kľúča, containsValue() testuje prítomnosť zadanej hodnoty, get() vracia hodnotu patriacu zadanému kľúču, put() priraďuje zadanému kľúču hodnotu, remove() odstraňuje kľúč z mapy, putAll() kopíruje do mapy všetky dvojice kľúč–hodnota z inej mapy, keySet() vracia množinu všetkých kľúčov (ako objekt typu Set), values() vracia množinu všetkých hodnôt (ako objekt typu Collection) a entrySet() vracia množinu všetkých dvojíc (ako objekt typu Set). Dvojice kľúč–hodnota, ktoré vracia posledná z vymenovaných metód, sú typu Map.Entry, čo je statické rozhranie deklarované v rozhraní Map. Na prácu s dvojicami toto rozhranie poskytuje metódy getKey(), setKey() a setValue() so samovysvetľujúcimi názvami.

Posledným údajovým rozhraním je SortedMap, teda usporiadaná mapa. Usporiadanie sa týka kľúčov a je podobne ako pri usporiadanej množine dané buď „prirodzene“, alebo prostredníctvom objektu typu Comparator. Nové metódy triedy SortedMap: comparator() vracia zadaný komparátor, subMap() vracia vybranú podmapu danej mapy, headMap() vracia časť mapy obsahujúcu kľúče menšie ako zadaný kľúč, tailMap() vracia časť mapy obsahujúcu kľúče väčšie alebo rovné ako zadaný kľúč a firstMap()/lastMap() vracia najmenší/najväčší kľúč mapy.

Iterátory

Iterátory sú údajové metaštruktúry, ktoré umožňujú k prvkom kolekcie pristupovať opakovane, v jednotlivých iteráciách cyklu. Balík java.util deklaruje dve iteračné rozhrania.

Prvé z nich, Iterator, sa používa pri iterovanom prístupe ku kolekciám. Obsahuje tieto metódy: hasNext() testuje, či možno sprístupniť ďalší prvok, next() sprístupní ďalší prvok a remove() odstráni prvok, vrátený posledným volaním next(), z kolekcie.

Druhé rozhranie, ListIterator, je potomkom rozhrania Iterator a poskytuje iterovaný prístup k prvkom zoznamu. Obsahuje niekoľko ďalších metód: hasPrevious() testuje, či možno sprístupniť predchádzajúci prvok, previous() sprístupní predchádzajúci prvok, nextIndex()/previousIndex() vracia index prvku, ktorý by bol sprístupnený nasledujúcim volaním next()/previous(), set() nahrádza prvok vrátený posledným volaním next()/previous() novým prvkom a konečne add() pridáva do zoznamu nový prvok, pred prvok, ktorý by bol vrátený nasledujúcim volaním next() a za prvok, ktorý by bol vrátený nasledujúcim volaním previous().

K prvkom zoznamov tak možno pristupovať buď náhodným spôsobom, pomocou ich indexov, alebo s použitím iterátorov, ktoré implementujú sekvenčný prístup. Príklad oboch spôsobov nájde čitateľ na webovej stránke PC REVUE.

Triedy kolekčného rámca

V balíku java.util sa okrem uvedených rozhraní nachádzajú aj ich rozličné implementácie.

Trieda AbstractCollection predstavuje skelet pre implementáciu rozhrania Collection. Slúži ako bázová trieda dvom ďalším triedam, AbstractList a AbstractSet. Tieto dve triedy sú analogicky skeletmi pre implementácie rozhraní List a Set. Do počtu chýba už len trieda AbstractMap, ktorá predstavuje skeletálnu implementáciu rozhrania Map.

Pozrime sa teraz na potomkov triedy AbstractList. Prvým z nich je ďalšia abstraktná trieda AbstractSequentialList. Aj táto trieda predstavuje kostru pre implementáciu rozhrania List, ale na rozdiel od triedy AbstractList, vhodnejšej na náhodný prístup k prvkom prostredníctvom indexu (takéto zoznamy sú obyčajne implementované pomocou poľa), je trieda AbstractSequentialList šitá na mieru sekvenčnému prístupu pomocou iterátorov. Triedy od nej odvodené môžu na implementáciu použiť napríklad zreťazený zoznam. Jedným takýmto potomkom je trieda LinkedList, ktorá realizuje dvojito zreťazený zoznam. Vďaka niekoľkým pridaným metódam ju možno efektívne použiť na implementáciu zásobníka, frontu i obojstranného frontu. Ide o tieto metódy: getFirst()/getLast() vracia prvý/posledný prvok zoznamu, removeFirst()/removeLast() odstraňuje a vracia prvý/posledný prvok zoznamu a addFirst()/addLast() pridáva nový prvok na začiatok/koniec zoznamu.

Ďalším potomkom triedy AbstractList je trieda ArrayList. Z jej názvu možno vydedukovať, že ide o spomínanú implementáciu zoznamu pomocou poľa. Každá inštancia triedy ArrayList má svoju kapacitu, ktorá sa zadáva ako argument konštruktora. V prípade, že sa celá kapacita poľa zaplní prvkami zoznamu, pole sa automaticky zväčšuje. Okrem známych metód nájdeme v triede ArrayList dve nové metódy: trimToSize() zmenší kapacitu poľa tak, aby bola rovná aktuálnej dĺžke zoznamu a ensureCapacity() explicitne zväčší kapacitu poľa na požadovanú veľkosť.

Nasledujúca trieda Vector (ešte stále hovoríme o potomkoch triedy AbstractList) je okrem malých detailov v zásade zhodná s triedou ArrayList. Dôvodom tejto duplicity je skutočnosť, že trieda Vector je súčasťou Javy prakticky „od začiatku“ a až od verzie 1.2 bola upravená tak, aby zapadla do kolekčného rámca. Vďaka tomu obsahuje oproti triede ArrayList aj niekoľko vlastných metód: copyInto() kopíruje prvky vektora do externého poľa, setSize() nastaví požadovanú veľkosť vektora (ak treba, dopĺňa prvky s hodnotou null, prípadne odstraňuje nadbytočné prvky), capacity() vracia aktuálnu kapacitu vektora, elements() vracia prvky vektora ako enumeráciu (pozri ďalej), elementAt() vracia prvok na danej pozícii, firstElement()/lastElement() vracia prvý/posledný prvok vektora, setElementAt() nastavuje hodnotu prvku na danej pozícii, removeElementAt() odstraňuje prvok na danej pozícii, insertElementAt() vkladá nový prvok do vektora na požadovanú pozíciu, addElement() pridáva prvok na koniec vektora, removeElement() odoberá požadovaný prvok z vektora a konečne removeAllElements() odstraňuje z vektora všetky prvky.

Vsuvka: enumerácia je objekt, ktorý dokáže postupne poskytovať objekty z nejakej skupiny. Takýto objekt musí implementovať rozhranie Enumeration, ktoré obsahuje dve metódy: hasMoreElements(), testujúcu, či je k dispozícii ešte nejaký prvok, a nextElement(), vracajúcu nasledujúci prvok skupiny.

Trieda Vector má jedného potomka – triedu Stack, implementujúcu zásobník, t. j. údajovú štruktúru s LIFO stratégiou prístupu. Na zjednodušenie práce táto trieda poskytuje nasledujúce metódy: empty() testuje, či je zásobník prázdny, peek() vracia objekt na vrchole zásobníka, pop() odstráni objekt z vrcholu zásobníka a vracia ho volajúcej metóde, push() vkladá objekt do zásobníka a search() vracia pozíciu daného objektu v zásobníku.

Toľko k zoznamom, pozrime sa na potomkov triedy AbstractSet, triedy HashSet a TreeSet. Prvá z nich, HashSet, je implementáciou množiny, založenou na hešovacej tabuľke. V konštruktore triedy možno zadať počiatočnú kapacitu i faktor vyťaženia tabuľky. Druhá trieda TreeSet implementuje usporiadanú množinu (t. j. SortedSet) pomocou tzv. Red-Black stromu.

Aby bol kolekčný rámec úplný, zostáva ešte spomenúť potomkov triedy AbstractMap. Tými sú triedy HashMap, TreeMap a WeakHashMap. Prvá z nich predstavuje mapu založenú na hešovacej tabuľke. Podobne ako pri HashSet možno zadať počiatočnú kapacitu aj faktor vyťaženia tabuľky. Trieda TreeMap realizuje usporiadanú mapu pomocou Red-Black stromu. Tretia z tried, WeakHashMap, je variantom triedy HashMap s tzv. slabými kľúčami – v prípade, že sa niektorý kľúč mapy už nepoužíva (mimo mapy naň neukazuje žiadna premenná), bude spolu so svojou asociovanou položkou z mapy odstránený.

Iné triedy

Medzi triedami realizujúcimi údajové štruktúry nájdeme v balíku java.util aj také, ktoré nie sú navrhnuté ako súčasť kolekčného rámca (predovšetkým preto, že sú staršie). Ide o triedy BitSet, Dictionary, Hashtable a Properties.

Trieda BitSet predstavuje vektor bitov (bitovú množinu), ktorý dokáže podľa potreby meniť svoju veľkosť. Jednotlivé bity (hodnoty typu boolean) sú prístupné pomocou celočíselného indexu. Trieda obsahuje tieto metódy: length() vracia „logickú“ dĺžku vektora, t. j. index najvyššieho nastaveného bitu + 1, set() nastavuje vybraný bit, clear() nuluje vybraný bit, andNot() vynuluje všetky bity, ktoré sú jednotkové v inej bitovej množine, get() vracia hodnotu vybraného bitu, and()/or()/xor() vykoná logickú operáciu AND/OR/XOR s inou bitovou množinou a size() vracia počet bitov v množine.

Ďalšia trieda Dictionary je abstraktná a predstavuje údajovú štruktúru schopnú mapovať kľúče na hodnoty. Považuje sa za zastaranú – na odvodzovanie nových tried sa odporúča použiť rozhranie Map. Jej potomok, trieda Hashtable, bola podobne ako Vector upravená tak, aby implementovala rozhranie Map. Vzťah medzi Hashtable a HashMap je zhruba rovnaký ako medzi Vector a ArrayList.

Trieda Properties je odvodená od Hashtable a reprezentuje perzistentnú množinu tzv. vlastností (to sú v podstate opäť dvojice kľúč–hodnota, kde hodnoty sú typu String). Parametrom konštruktora triedy Properties môže byť iná inštancia tejto triedy – ako „implicitný“ zoznam vlastností – ktorá sa prehľadá v prípade neúspešného hľadania kľúča v primárnom zozname. Nové metódy triedy: setProperty()/getProperty() nastavuje/vracia hodnotu vybranej vlastnosti, load() načíta zoznam vlastností zo vstupného prúdu, store() zapíše zoznam vlastností do výstupného prúdu, propertyNames() vracia enumeráciu všetkých kľúčov v zozname a list() vypíše celý zoznam na zadaný výstupný prúd. Trieda Properties sa používa aj pri práci so systémovými vlastnosťami JVM.

Posledné dve triedy balíka java.util, ktoré súvisia s údajovými štruktúrami, sú triedy Arrays a Collections. Obe obsahujú výhradne statické metódy, určené na prácu s poľami a s kolekciami. Trieda Arrays poskytuje tieto metódy: sort() usporiada pole alebo jeho časť buď vzostupne, na základe „prirodzeného“ usporiadania, alebo podľa objektu typu Comparator, binarySearch() slúži na binárne vyhľadanie hodnoty v (usporiadanom!) poli, equals() porovnáva dve polia, fill() vyplní pole alebo jeho časť zadanou hodnotou a asList() vráti pole vo forme objektu typu List.

V triede Collections nájdeme metódy sort(), binarySearch(), fill(), ktoré sú zoznamovým ekvivalentom rovnakých metód triedy Arrays, a ďalej tieto metódy: reverse() obráti poradie prvkov v zozname, shuffle() vyrobí náhodnú permutáciu prvkov zoznamu, copy() skopíruje jeden zoznam do druhého, min()/max() vracia najmenší/najväčší prvok zoznamu, unmodifiableXXX()/synchronizedXXX(), kde XXX je jedno zo šiestich kolekčných rozhraní, vracia nemodifikovateľnú/synchronizovanú verziu príslušnej údajovej štruktúry, singleton()/singletonList()/singletonMap() vracia množinu/zoznam/mapu obsahujúcu len zadaný objekt, nCopies() vracia zoznam pozostávajúci z požadovaného počtu kópií zadaného objektu, reverseOrder() vracia komparátor špecifikujúci obrátené usporiadanie k prirodzenému usporiadaniu a nakoniec enumeration() vracia enumeráciu nad danou kolekciou.

Dátum a čas

Ďalším okruhom, ktorý balík java.util pokrýva, sú triedy na prácu s dátumovými a časovými údajmi.

Trieda Date reprezentuje časový bod (určený dátumom a časom) univerzálneho času UTC s presnosťou na milisekundy. Má dva konštruktory – prvý bez argumentov vytvorí objekt reprezentujúci aktuálny systémový čas, druhý akceptuje jeden argument typu long, ktorý udáva počet milisekúnd od polnoci 1. 1. 1970 GMT (ďalej „unixový čas“). Metódy triedy: getTime() vracia ekvivalentný unixový čas, setTime() umožňuje nastaviť objekt Date na základe unixového času, before() testuje, či sa časový bod nachádza pred iným časovým bodom, after() podobne testuje, či sa časový bod nachádza za iným časovým bodom a compareTo() porovnáva časový bod s iným časovým bodom. Metóda toString(), zdedená z triedy Object, konvertuje dátum/čas na reťazec tvaru: Sun Jul 22 20:07:47 GMT+02:00 2001.

V bežnom živote sa časové údaje vyjadrujú pomocou rokov, mesiacov, dní, hodín, minút a sekúnd. Na konverziu medzi takýmto vyjadrením a objektom typu Date slúži abstraktná trieda Calendar a jej potomok GregorianCalendar, reprezentujúci gregoriánsky kalendárny systém. Opis týchto dvoch tried a práce s nimi by zabral pomaly aj samostatný článok, preto sa uspokojíme s uvedením najdôležitejších metód: getTime() vracia ekvivalentný objekt Date, setTime() nastaví dátum/čas na základe zadaného objektu Date, get() vracia vybranú zložku dátumu/času, set() umožňuje nastaviť vybranú zložku dátumu/času, before()/after() sa správajú podobne ako v triede Date, add() umožňuje posun časového bodu o zadaný interval, roll() je podobná metóde add(), nemení však hodnotu „vyšších“ zložiek. Na ilustráciu rozdielu medzi add() a roll(): posunom dátumu 1. 11. 2001 o tri mesiace dopredu pomocou add() dostaneme dátum 1. 2. 2002, posunom pomocou roll() dátum 1. 2. 2001 (t. j. zmenil sa len mesiac).

S dátumom a časom čiastočne súvisia aj ďalšie triedy: TimeZone, SimpleTimeZone a Locale. Prvé dve z nich slúžia na opis časových zón, vyjadrený odchýlkou od GMT (do úvahy sa berie aj letný čas, DST) – SimpleTimeZone je implementáciou abstraktnej triedy TimeZone. Tretia trieda Locale reprezentuje národné prostredia s kódmi podľa štandardu ISO. Ich bližší opis by bol istotne zaujímavý, ale, bohužiaľ, nemáme naň miesto.

Ostatné triedy

Zo zvyšných tried v balíku java.util medzi dôležitejšie patria ešte triedy Observable, Random, StringTokenizer, Timer a TimerTask.

Trieda Observable predstavuje základ pre objekty, ktoré z nejakého dôvodu chceme pozorovať a v okamihu zmeny ich stavu o tom upozorniť iné objekty. „Pozorovacie“ objekty musia implementovať rozhranie Observer, obsahujúce jedinú metódu update(), ktorá sa vyvolá ako reakcia na zmenu pozorovaného objektu. Medzi metódy triedy Observable patria: addObserver()/deleteObserver() pridáva/odoberá pozorovateľov, notifyObservers() „obvolá“ všetkých pozorovateľov a oznámi im, že sa stav pozorovaného objektu zmenil, setChanged()/clearChanged() nastavuje/maže príznak zmeny objektu, hasChanged() indikuje, či sa objekt zmenil, a countObservers() vracia počet aktuálne pripojených pozorovateľov.

Inštancie triedy Random generujú prúd pseudonáhodných čísel. Na získanie náhodného čísla požadovanej bitovej šírky slúži metóda next() a niekoľko jej variantov, ktoré dokážu vrátiť náhodné číslo zadaného typu, prípadne aj so zadaným rozdelením (rovnomerné, normálne).

Trieda StringTokenizer sa používa na „rozbitie“ reťazca na postupnosť tokenov. Pri konštruovaní možno zadať oddeľovače, implicitne sa predpokladajú biele znaky. StringTokenizer implementuje rozhranie Enumeration, nájdeme v nej teda metódy hasMoreElements() a nextElement() (vracia typ Object), ako aj vlastné metódy hasMoreTokens(), nextToken() (vracia typ String) a countTokens(). Názvy metód sú samovysvetľujúce.

Posledné dve triedy Timer a TimerTask slúžia na implementáciu plánovača úloh. Ich činnosť čiastočne súvisí s threadmi, preto ich zatiaľ preskočíme. V budúcnosti sa k nim ešte vrátime.

Výnimky

V balíku java.util nájdeme deklaráciu niekoľkých výnimiek. Z tých podstatných vyberáme: ConcurrentModificationException indikuje pokus o súčasnú modifikáciu údajovej štruktúry dvoma rôznymi threadmi, EmptyStackException sa vyskytne pri snahe vyberať údaje z prázdneho zásobníka, NoSuchElementException dostaneme pri pokuse o sprístupnenie neexistujúceho prvku enumerácie.

Nabudúce

V budúcom pokračovaní sa pozrieme na dva podbalíky java.util.zip a java.util.jar a azda aj na minule avizovaný sieťový balík java.net.

 

 

 


Nechajte si posielať prehľad najdôležitejších správ emailom

Mohlo by Vás zaujímať

Ako na to

Tipy a triky: Ako na snímku obrazovky na akomkoľvek počítači s Windows?

02.12.2016 00:13

Ak snímky obrazovky robíte často apotrebujete napríklad funkcie na posun stránok alebo snímanie zobrazenia pri vyššom rozlíšení displeja, zrejme používate nejakú špecializovanú aplikáciu. Väčšina použ ...

Ako na to 1

Tipy a triky: Ako aplikácii prednastaviť spúšťanie s administrátorskými právami?

30.11.2016 00:10

Väčšina aspoň trochu skúsenejších používateľov vie, že aj keď máte na operačnom systéme Windows vytvorený administrátorský účet, aplikácie pre bezpečnosť nefungujú vždy splnými administrátorskými práv ...

Ako na to 2

Tipy a triky: Ako vypnúť uzamykaciu obrazovku vo Windows 10?

29.11.2016 00:10

Rozčuľuje vás, že pred každým prihlásením doúčtu vášho počítača musíte prejsť uzamykacou obrazovkou? Windows 10 na tejto obrazovke ukazuje čas,dátum anejakú zaujímavú fotografiu zrôznych kútov sveta. ...

Žiadne komentáre

Vyhľadávanie

Kyocera - prve-zariadenia-formatu-a4-s-vykonom-a3

Najnovšie videá