V tomto úvodnom článku do série pokročilá java sa pozrieme na zúbok kolekciám. Kolekcie sú akoby kontajnery, ktoré v sebe držia ďalšie objekty. Inak môžeme kolekcie chápať aj ako zoznamy. Zoznam telefónnych čísiel. Zoznam osôb. Zoznam áut. Zoznam súborov. Zoznam čísiel ….
Pri kolekciách budeme hovoriť o Rozhraní, Implementácii a Algoritmoch.
Java collection framework – java sama o sebe poskytuje niekoľko kolekcií. Poskytuje nám ich implementácie a aj algoritmy na vyhľadávanie, vkladanie, triedenie a podobne.
Rozhriania kolekcií v tomto frameworku sú generické. Teda umožňujú do nich vkladať rôzne typy objektov. Pamätajte, že java je striktne typový jazyk a do premennej typu String proste int nedáš, musí tam ísť iba String. Ku generikám sa ešte dostaneme neskoršom článku.
Zoznam rozhraní Java collection frameworku:
Collection – top v hierarchii, používa sa na presun kolekcii, manipuláciu kde sa požaduje aby tam prišla akákoľvek kolekcia. Do Collection môžeš vložiť akýkoľvek typ kolekcie, ktorý rozširuje túto kolekciu.
Set – nemôže obsahovať duplicity
List – zoznam, môže obsahovať duplicity, poradie elementov je zachované pomocou indexov
Queue – FIFO – first in first out, čo príde prvé do tejto kolekcie tak z nej aj prvé odíde, niektoré implementácie majú výnimky
Deque – FIFO aj LIFO (last in first out) – elementy môžu byť vkladané aj vyberané z oboch koncov
Map – object ktorý mapuje objekty k ich kľúčom, nemôže obsahovať totožné kľúče
SortedSet a SortedMap – sú vlastne zoradené Map a Set
Implementácie (najpoužívanejšie sú zvýraznené boldom):
Set |
EnumSet, HashSet, LinkedHashSet, TreeSet |
List |
ArrayList, LinkedList, Stack, Vector |
Map |
EnumMap, HashMap, LinkedHashMap, TreeMap |
SortedSet NavigableSet |
TreeSet |
SortedMap NavigableMap |
TreeMap |
Queue |
LinkedList, PriorityQueue |
Set
Neobsahuje duplicitné elementy – lepšie povedané nemôže obsahovať duplicitné elementy.
HashSet – neuchováva poradie v akom boli elementy vložené ale pracuje najrýchlejšie
LinkedHashSet – uchováva poradie elementov v akom boli vložené
TreeSet – poradie elementov je zoradené podľa ich hodnôt, je pomalší
Majme kolekciu, ktorá obsahuje elementy, ktoré sú duplicitné. Ako z nej najrýchlejšie získame kolekciu, ktorá nemá duplicity?
Collection<Type> noDups = new HashSet<Type>(c);
Funguje to tak, že z kolekcie sa vytvorí Set. A Set už z definície nemôže obsahovať duplicity.
Pridanie elementov do Setu:
Set<String> set1 = new HashSet<>();
String s = "e";
set1.add("element1");
set1.add("element2");
set1.add("element3");
set1.add("element4");
set1.add(s);
Je element v kolekcii?
System.out.println(set1.contains("e")); //true
Odstránenie elementu z kolekcie:
set1.remove(s);
Prechádzanie cez Set:
Iterator i = set1.iterator();
while (i.hasNext()){
System.out.println(i.next());
}
for(String s : set1) {
System.out.println(s);
}
Spýtam sa či všetky elementy zo set1 sú aj v set2
set1.containsAll(set2));
Odstránim z set1 všetky zhodné elementy so set2
set1.removeAll(set2);
Všetko zo set2 pridám do set1
set1.addAll(set2);
List
Uchováva poradie elementov. Elementy sú prístupné aj pomocou indexov. Je možné do už vytvoreného Listu pridať nové elementy aj na indexy ktoré sú obsadené – elementy sa posunú. Môžeme v nich vyhľadávať indexOf a lastIndexOf. Pri Listoch si musíme dávať veľký pozor na to aby sme nezhodili program kvôli prístupu k neexistujúcim elementom – respektíve k neexistujúcim indexom v Liste. Napríklad máš List so 4 elementami a chceš pristúpiť k 6temu elementu.
Základné pomocné algoritmy, špecifické ku List:
- sort — zotriedi elementy v Liste
- shuffle — náhodne pomieša elementy v Liste.
- reverse — otočí poradie elementov v Liste
- rotate — otočí poradie všetkých elementov od špecifického indexu
- swap — prehodí elementy z Listu na špecifikovaných indexoch
- replaceAll — nahradí všetky výskyty špecifikovanej hodnoty za druhú špecifikovanú hodnotu
- fill — prepíše všetky elementy v Liste za špecifikovanú hodnotu
ArrayList – prispôsobuje svoju veľkosť, základné polia museli mať špecifikovanú dĺžku pri vytvorení, nemohli rásť alebo sa zmenšovať
LinkedList – iná implementácia, rozdielu sú v časových záťažiach s rôznymi operáciami nad Listami
Pridanie elementov do Listu:
List<String> list = new ArrayList<>();
list.add("list1");
list.add("list2");
list.add("list3");
list.add("list4");
list.add("list5");
Výber elementu z listu na indexy 1:
list.get(1);
Je prázdny?
list.isEmpty();
Pridaj na pozíciu 2:
list.add(2,"list2b");
Odstráň element:
list.remove("list1");
list.remove(4);
Rôzne manipulácie:
Collections.sort(list);
Collections.shuffle(list);
Collections.reverse(list);
Collections.rotate(list,2);
Collections.swap(list, 0, 1);
Collections.replaceAll(list, "list4", "new list4");
Collections.fill(list,"Jaro");
Map
Mapa obsahuje hodnoty viazané na kľuč. Takže to máme po anglicky key – value hodnoty. Kľúče musia byť unikátne.
HashMap – nedrží si poradie, náhodné usporiadanie
LinkedHashMap – drží poradie
Vloženie do Mapy:
Map<Integer,String> map = new HashMap<>();
map.put(10,"jaro");
map.put(1,"fero");
map.put(3,"duro");
map.put(4000,"karol");
map.put(4000,"peter"); // prepise predchádzajúci element
Získame a vypíšeme hodnotu elementu s kľúčom 1:
System.out.println(map.get(1));
Prechod cez elementy Mapy:
for(Map.Entry m : map.entrySet()){
System.out.printf("key %d, value %s %n",m.getKey(),m.getValue());
}
for(Integer k : map.keySet()){
map.get(k);
}
Zoradovanie
Pre zoraďovanie použijeme už existujúci algoritmus v triede Collections.sort(l). Písmeno l v tomto prípade bude List. Ak by tento List obsahoval sadu Stringov boli by zoradené abecende, ak by obsahoval Dátum tak budú zoradené chronologicky. Ako je to možné? Je to preto, lebo tieto triedy implementujú rozhranie Comparable. Ak by si sa snažil takto zoradiť také triedy, ktoré neimplementujú toto rozhranie, tak program vyhodí výnimku.
Existuje ale možnosť, že v tvojej triede implementuješ toto rozhranie. Potom toto triedenie je teraz považované za prirodzené.
Príklad: Máme Osobu, ktorá implementuje Comparable. Musíme implementovať metódu compareTo.
public class Osoba implements Comparable<Osoba>{
private String meno;
private String priezvisko;
private int vek;
public Osoba(String meno, String priezvisko, int vek) {
this.meno = meno;
this.priezvisko = priezvisko;
this.vek = vek;
}
//get, set metódy vynechané pre čitatelnosť
@Override
public String toString() {
return "Osoba{" +
"meno='" + meno + '\'' +
", priezvisko='" + priezvisko + '\'' +
", vek=" + vek +
'}';
}
@Override
public int compareTo(Osoba o) {
int porovnaniePriezvisk = o.getPriezvisko().compareTo(this.getPriezvisko());
return porovnaniePriezvisk !=0 ? porovnaniePriezvisk : o.getMeno().compareTo(this.getMeno());
}
}
Čo ak chceš použiť úplne iné ako prirodzené triedenie, chceš to triediť napríklad podľa veku. Alebo chceš triediť objekty, ktoré neimplementujú Comparable rozhranie? Tak si ho vyrobíš. Na to použiješ rozhranie Comparator a potom ho požiješ Collections.sort(e, VLASTNY_ORDER);.
public class Sort {
private static final Comparator<Osoba> VEK_TRIEDENIE = new Comparator<Osoba>() {
@Override
public int compare(Osoba o1, Osoba o2) {
return Integer.compare(o1.getVek(), o2.getVek());
}
};
public static void main(String[] args) {
Osoba[] osobyArray = {
new Osoba("Jaro", "Beno", 20),
new Osoba("Peter", "Beno", 25),
new Osoba("Karol", "Slepec", 18),
new Osoba("Tomas", "Vlak", 22)
};
List<Osoba> osoby = Arrays.asList(osobyArray);
System.out.println(osoby);
Collections.sort(osoby);
System.out.println(osoby);
Collections.sort(osoby, VEK_TRIEDENIE);
System.out.println(osoby);
}
}