|
||||||||||||||||||||||||||||||||||||||||||||||||
Menu
Distributions (131)
Software (10844)
|
Java (12) - Kontejnery III.Pojednání o kontejnerech by nebylo úplné, kdybychom vynechali algoritmy, které
nad nimi pracují. Také se podíváme na nové (a vesměs příjemné) věci, které
se do The Collections Framework dostaly v Javě 5.0.
Algoritmy
Implementace algoritmů pro práci s kolekcemi jsou shromážděny ve třídě
Seřazení seznamu
Máme nějaký obecný seznam (tj. nějakou implementaci rozhraní List list = new ArrayList(); // vytvoření seznamu ... // naplnění atd. Collections.sort(list); // seřazení Promíchání seznamu
Opakem seřazení je náhodné zamíchání seznamu. I to se může občas hodit (a to
nejen v případě, že chceme přehrávat písničky v náhodném pořadí). I zde jsou
metody dvě ( List list = new LinkedList(); // vytvoření seznamu ... // naplnění atd. Collections.shuffle(list); // promíchání Obrácení pořadí
Opět velmi jednoduchá, avšak užitečná činnost. Poskytuje ji metoda Hledání binárním dělením
Podobně jako u polí, i u seřazených seznamů může s úspěchem použít hledání
binárním dělením. Pro seznamy s možností náhodného přístupu (tj. implementující
rozhraní List list = new ArrayList(); // vytvoření seznamu list.add("abc"); // vložíme prvky list.add("efg"); list.add("cde"); Collections.sort(list); // seřazení System.out.print("Hledaný řetězec má pozici "); System.out.println(Collections.binarySearch(list, "efg")); // vypíše "2" Plnění seznamuOpět zjevná analogie s poli, co k tomu říci více... List list = new ArrayList(); // vytvoření seznamu list.addAll(Collections.nCopies(100, new Double(3.3))); // první naplnění Collections.fill(list, new Double(5.0)); // další naplnění Kopírování seznamu
Zkopírovat seznam lze v zásadě třemi cestami. Jednou je vytvoření úplně nového
seznamu pomocí "kopírovacího" konstruktoru (v uvozovkách proto, že zde nejde
o skutečný kopírovací konstruktor). Tím se vytvoří nový seznam
obsahující prvky toho původního (resp. obecněji, prvky libovolné kolekce
implementující rozhraní List list1 = new ArrayList(); // vytvoření prvního seznamu ... // nějaké operace List list2 = new LinkedList(list1); // nový seznam obsahuje všechny prvky původního
Druhou možností je volání statické metody List list1 = new ArrayList(); // vytvoření prvního seznamu ... // nějaké operace List list2 = new LinkedList(); // vytvoření druhého seznamu Collections.copy(list2, list1); // kopírujeme
Třetí způsob není v podstatě skutečné kopírování, vytváří totiž pouze pohled
na tentýž seznam (při modifikaci se mění data v nové i v původním seznamu).
Používáme metodu List list1 = new ArrayList(); // vytvoření prvního seznamu ... // nějaké operace List list2 = list1.subList(0, 10); // získání podseznamu list2.set(0, list2.get(1)); // zkopíruje prvek z pozice 1 na pozici 0 (v obou seznamech!) Konverze kolekcí na pole a naopak
Běžné kolekce lze převádět na normální pole dvojicí metod List list = new ArrayList(); // vytvoření seznamu Object oa[] = list.toArray(); // převedení na pole objektů String sa[] = (String[]) list.toArray(new String[0]); // převedení na pole řetězců
Opačným případem je vytvoření seznamu (nebo jiné kolekce) z pole. K tomu
slouží statická metoda String sa[] = new String[10]; // vytvoření pole ... // naplnění apod. List list = Arrays.asList(sa); // vytvoření neměnného seznamu nad polem list.add("bbbb"); // nelze - způsobí výjimku UnsupportedOperationException list = new List(list); // zkopírujeme seznam list.add("bbbb"); // tohle už lze Zjišťování informací o prvcích
Ve třídě
Máme zde metody Set set = new HashSet(); ... System.out.println("Minimum: " + Collections.min(set)); System.out.println("Maximum: " + Collections.max(set));
Dvojice metod Ostatní algoritmy
Seznam můžeme "zrotovat" o určitý počet pozic. Použijeme k tomu metodu
Novinky v kontejnerech od Javy 5.0Java 5.0 (tedy JDK 1.5) přináší dost podstatné změny v rozhraní i implementaci kolekcí. Byly tak vyslyšeny časté stížnosti některých programátorů na napříliš bezpečný způsob práce s kolekcemi, na složité používání primitivních typů a další problémy. Současně přibyly některé funkce, které usnadňují práci s kontejnery. Podívejme se tedy blíže... Typová bezpečnostProgramátoři v C++ jsou zvyklí, že pokud potřebují nějaký kontejner, vytvoří si instanci příslušné šablony s takovým typem, kterého jsou vkládané hodnoty. Pro takovou práci dříve javovské kolekce neposkytovaly žádnou podporu, do kontejneru bylo možné vkládat prakticky cokoliv a pokud někdo vyžadoval typovou bezpečnost, musel si vše ošetřit sám. Nová verze Javy ale přináší podstatnou změnu. Nyní lze vytvořit typově určený kontejner, čímž máme zaručeno, že prvky v něm obsažené budou konkrétního typu. Pokus o porušení typové kontroly bude ohlášen již během kompilace. Podmínkou ale je, aby byl kontejner nejen vytvořen jako typový (tj. při volání konstruktoru), ale musí tak být deklarována příslušná proměnná. Kolekce bez typové kontroly lze nadále používat, kompilátor však bude vypisovat varování. // starý způsob - chceme pracovat jen s celými čísly List list = new ArrayList(); // seznam bez určení typu list.add(new Integer(5)); // vložíme číslo... list.add(""); // ...ale klidně i něco jiného // nový způsob List<Integer> list = new ArrayList<Integer>(); // seznam celých čísel list.add(new Integer(5)); // vložíme číslo... list.add(""); // ...a tohle by kompilátor nedovolil
Uvedený způsob typové kontroly má jednu nevýhodu - je statický, takže
lze použít jen tam, kde typ známe předem. V řadě případů je tomu však jinak,
proto musíme použít dynamickou typovou kontrolu. Máme k dispozici wrappery
na generování typově bezpečných kolekcí, které se používají podobně jako jiné
wrappery (viz minulý díl). Při pokusu o porušení ochrany je vyvolána výjimka
// vytváření seznamu - použijeme wrapper List<Integer> list = Collections.checkedList(new ArrayList<Integer>(), Integer.class); ForeignObj obj = new ForeignObj(); obj.setList(list) // nyní se seznam někam předá... // ...a tam to může vypadat třeba takto: public class ForeignObj { ... public void setList(List lst) { lst.add(new Integer(5)); // tohle je v pořádku lst.add("abc"); // tohle v pořádku není a způsobí to ClassCastException } } Přímá práce s primitivními typy
Komplikací při práci s primitivními typy ( List<Double> list = new ArrayList<Double>(); // seznam celých čísel list.add(new Double(2.75)); // starý způsob list.add(2.75); // nový způsob Speciální cykly pro snadnou iteraci
Při sekvenčním přístupu k prvkům přes iterátor jsme museli napsat poměrně
hodně kódu, který se při každém takovém použití opakoval. Proto vznikla
(opět podle mého názoru nepříliš čistá) berlička, spočívající v "rozšířeném"
(resp. speciálním) cyklu List<String> list = new ArrayList<String>(); // původní způsob (klasický cyklus) for (Iterator<String> i = list.iterator(); i.hasNext(); ) { System.out.println(i.next()); } // nový způsob (rozšířený cyklus for) for (String s : list) { System.out.println(s); } Fronty
Často používanými strukturami jsou fronty, proto se dostaly i do CF. Máme
zde nová rozhraní - Kolekce "téměř jen ke čtení"
V řadě případů kolekci někdy na počátku vytvoříme a pak už se nemění buď
vůbec, nebo jen zřídka. Pro takové situace se hodí implementace, která
zajišťuje maximální rychlost při operacích čtení, bez ohledu na rychlost
manipulačních operací. V Javě 5.0 tuto skupinu reprezentují třídy
Nové algoritmy
Ve třídě
Možná toho bylo o kolekcích až příliš, ale doufám, že to nevadí. Příště se vrátíme až na úplný začátek a povíme si zase něco o psaní programů, kompilaci, spouštění apod. Od doby, kdy seriál začal (tj. od loňského léta) se totiž leccos změnilo, současně tím ale budu reagovat i na reakce čtenářů, že by rádi do těchto věcí pronikli hlouběji
|
Search Software
Search Google
|
||||||||||||||||||||||||||||||||||||||||||||||
©Pavel Kysilka - 2003-2024 | maillinuxsoft.cz | Design: www.megadesign.cz |