Java Collections: alatka napravljena za okvir kolekcija
Collections je alatka koju pruža JDK, nalazi se u paketu java.util i pruža niz statičkih metoda koje nam olakšavaju izvođenje raznih operacija nad kolekcijama — može se reći da je glavni domaćin okvira za kolekcije.
Sećate li se Arrays alatke o kojoj smo ranije govorili? Možete se vratiti i ponoviti gradivo.
Korišćenje Collections-a je vrlo jednostavno: u IntelliJ IDEA, nakon što otkucate Collections., videćete metode koje pruža; pogledom na ime metode i parametre uglavnom možete zaključiti čemu služi.

Da bismo vam uštedeli vreme u učenju, grupisao sam ove metode i naveo nekoliko jednostavnih primera.
01,Operacije sortiranja
reverse(List list): obrće redosledshuffle(List list): mešanje, nasumično raspoređuje redosledsort(List list): prirodni rastući redosledsort(List list, Comparator c): sortira prema prilagođenom komparatoruswap(List list, int i, int j): menja mesta elementima na pozicijama i i j
Pogledajmo primer:
List<String> list = new ArrayList<>();
list.add("Chenmo Wang Er");
list.add("Chenmo Wang San");
list.add("Chenmo Wang Si");
list.add("Chenmo Wang Wu");
list.add("Chenmo Wang Liu");
System.out.println("Originalni redosled: " + list);
// obrtanje
Collections.reverse(list);
System.out.println("Nakon obrtanja: " + list);
// mešanje
Collections.shuffle(list);
System.out.println("Nakon mešanja: " + list);
// prirodni rastući redosled
Collections.sort(list);
System.out.println("Nakon prirodnog rastućeg redosleda: " + list);
// zamena
Collections.swap(list, 2,4);
System.out.println("Nakon zamene: " + list);Izlaz:
Originalni redosled: [Chenmo Wang Er, Chenmo Wang San, Chenmo Wang Si, Chenmo Wang Wu, Chenmo Wang Liu]
Nakon obrtanja: [Chenmo Wang Liu, Chenmo Wang Wu, Chenmo Wang Si, Chenmo Wang San, Chenmo Wang Er]
Nakon mešanja: [Chenmo Wang Wu, Chenmo Wang Er, Chenmo Wang Liu, Chenmo Wang San, Chenmo Wang Si]
Nakon prirodnog rastućeg redosleda: [Chenmo Wang Er, Chenmo Wang Liu, Chenmo Wang San, Chenmo Wang Si, Chenmo Wang Wu]
Nakon zamene: [Chenmo Wang Er, Chenmo Wang Liu, Chenmo Wang Si, Chenmo Wang San, Chenmo Wang Wu]02,Operacije pretrage
binarySearch(List list, Object key): binarna pretraga, pod uslovom da je List već sortiranmax(Collection coll): vraća najveći elementmax(Collection coll, Comparator comp): prema prilagođenom komparatoru, vraća najveći elementmin(Collection coll): vraća najmanji elementmin(Collection coll, Comparator comp): prema prilagođenom komparatoru, vraća najmanji elementfill(List list, Object obj): popunjava zadatim objektomfrequency(Collection c, Object o): vraća broj pojavljivanja zadatog objekta
Pogledajmo primer:
System.out.println("Najveći element: " + Collections.max(list));
System.out.println("Najmanji element: " + Collections.min(list));
System.out.println("Broj pojavljivanja: " + Collections.frequency(list, "Chenmo Wang Er"));
// binarna pretraga bez prethodnog sortiranja daje nesiguran rezultat
System.out.println("Rezultat binarne pretrage pre sortiranja: " + Collections.binarySearch(list, "Chenmo Wang Er"));
Collections.sort(list);
// nakon sortiranja, rezultat pretrage je u skladu sa očekivanjem
System.out.println("Rezultat binarne pretrage nakon sortiranja: " + Collections.binarySearch(list, "Chenmo Wang Er"));
Collections.fill(list, "Chenmo Wang Ba");
System.out.println("Rezultat nakon popunjavanja: " + list);Izlaz:
Originalni redosled: [Chenmo Wang Er, Chenmo Wang San, Chenmo Wang Si, Chenmo Wang Wu, Chenmo Wang Liu]
Najveći element: Chenmo Wang Wu
Najmanji element: Chenmo Wang Er
Broj pojavljivanja: 1
Rezultat binarne pretrage pre sortiranja: 0
Rezultat binarne pretrage nakon sortiranja: 0
Rezultat nakon popunjavanja: [Chenmo Wang Ba, Chenmo Wang Ba, Chenmo Wang Ba, Chenmo Wang Ba, Chenmo Wang Ba]03,Sinhronizacija
HashMap nije bezbedan za niti, o tome smo već govorili. Zapravo, ni ArrayList nije bezbedan za niti i ne može se koristiti u višenitnom okruženju. Zato Collections alatka pruža više synchronizedXxx metoda koje vraćaju sinhronizovani objekat, čime se rešava problem bezbednosti pri pristupu kolekcijama iz više niti.

Korišćenje je takođe vrlo jednostavno:
SynchronizedList synchronizedList = Collections.synchronizedList(list);Pogled na izvorni kod SynchronizedList-a i sve je jasno: samo je unutar metoda dodat sloj katanca pomoću ključne reči synchronized.
static class SynchronizedList<E>
extends SynchronizedCollection<E>
implements List<E> {
private static final long serialVersionUID = -7754090372962971524L;
final List<E> list;
SynchronizedList(List<E> list) {
super(list); // poziva konstruktor nadklase SynchronizedCollection, prosleđuje list
this.list = list; // inicijalizuje član list
}
// vraća element na zadatom indeksu
public E get(int index) {
synchronized (mutex) {return list.get(index);} // pod katancem, poziva get metodu liste
}
// umeće zadati element na zadati indeks
public void add(int index, E element) {
synchronized (mutex) {list.add(index, element);} // pod katancem, poziva add metodu liste
}
// uklanja element na zadatom indeksu
public E remove(int index) {
synchronized (mutex) {return list.remove(index);} // pod katancem, poziva remove metodu liste
}
}Onda je, dakle, efikasnost približno ista kao kod Vector-a i Hashtable-a koji direktno stavljaju ključnu reč synchronized na metode (postoje još od JDK 1.0), a te klase kolekcija su u suštini napuštene i gotovo da se ne koriste.
public class Vector<E>
extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
// vraća element na zadatom indeksu
public synchronized E get(int index) {
if (index >= elementCount) // ako indeks prelazi veličinu liste, baca izuzetak o prekoračenju granica niza
throw new ArrayIndexOutOfBoundsException(index);
return elementData(index); // vraća element na zadatom indeksu
}
// uklanja element na zadatom indeksu
public synchronized E remove(int index) {
modCount++; // brojač izmena, označava da je lista izmenjena
if (index >= elementCount) // ako indeks prelazi veličinu liste, baca izuzetak o prekoračenju granica niza
throw new ArrayIndexOutOfBoundsException(index);
E oldValue = elementData(index); // uzima element na zadatom indeksu
int numMoved = elementCount - index - 1; // izračunava koliko elemenata treba pomeriti
if (numMoved > 0) // ako ima elemenata za pomeranje
System.arraycopy(elementData, index+1, elementData, index,
numMoved); // pomiče elemente niza za jedno mesto ulevo
elementData[--elementCount] = null; // poslednji element se postavlja na null, čeka ga sakupljanje smeća
return oldValue; // vraća uklonjeni element
}
}Ispravan pristup je korišćenje CopyOnWriteArrayList i ConcurrentHashMap iz paketa za istovremeni rad. O njima će biti reči kada budemo obrađivali istovremeno programiranje.
04,Nepromenljive kolekcije
emptyXxx(): pravi praznu nepromenljivu kolekcijusingletonXxx(): pravi nepromenljivu kolekciju sa samo jednim elementomunmodifiableXxx(): za zadatu kolekciju pravi nepromenljivu kolekciju
Na primer:
List emptyList = Collections.emptyList();
emptyList.add("neprazno");
System.out.println(emptyList);Ovaj kod će pri izvršavanju baciti grešku.
Exception in thread "main" java.lang.UnsupportedOperationException
at java.util.AbstractList.add(AbstractList.java:148)
at java.util.AbstractList.add(AbstractList.java:108)
at com.itwanger.s64.Demo.main(Demo.java:61)To je zato što Collections.emptyList() vraća internu klasu Collections-a, EmptyList, a EmptyList ne redefiniše metod add(int index, E element) nadklase AbstractList, pa pri izvršavanju baca UnsupportedOperationException koji ukazuje na to da operacija nije podržana.
Do ovog zaključka se došlo analizom izvornog koda add metoda. Pored toga, metod emptyList je final, i vraćeni EMPTY_LIST je takođe final — sve ukazuje na to da emptyList vraća nepromenljiv objekat nad kojim nije moguće vršiti dodavanje, brisanje ni izmenu.
public static final <T> List<T> emptyList() {
return (List<T>) EMPTY_LIST;
}
public static final List EMPTY_LIST = new EmptyList<>();05,Ostalo
Još dve metode se često koriste:
addAll(Collection<? super T> c, T... elements), dodaje elemente u kolekcijudisjoint(Collection<?> c1, Collection<?> c2), proverava da li dve kolekcije nemaju presek
Na primer:
List<String> allList = new ArrayList<>();
Collections.addAll(allList, "Chenmo Wang Jiu","Chenmo Wang Shi","Chenmo Wang Er");
System.out.println("Nakon addAll: " + allList);
System.out.println("Da li nema preseka: " + (Collections.disjoint(list, allList) ? "da" : "ne"));Izlaz:
Originalni redosled: [Chenmo Wang Er, Chenmo Wang San, Chenmo Wang Si, Chenmo Wang Wu, Chenmo Wang Liu]
Nakon addAll: [Chenmo Wang Jiu, Chenmo Wang Shi, Chenmo Wang Er]
Da li nema preseka: ne06,CollectionUtils: alatka za kolekcije koju nude i Spring i Apache
Za rad sa kolekcijama, pored već pomenute izvorne JDK Collections alatke, često se koristi i CollectionUtils alatka.
Trenutno je najzastupljenija CollectionUtils alatka iz paketa org.springframework.util okvira Spring.

I CollectionUtils alatka iz paketa org.apache.commons.collections okvira Apache.

Maven koordinate su sledeće:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.4</version>
</dependency>Apache ima nešto više metoda od Spring-a, pa ćemo uzeti Apache kao primer i predstaviti često korišćene metode.
Provera da li je kolekcija prazna
Pomoću metode isEmpty alatke CollectionUtils lako se proverava da li je kolekcija prazna, dok metod isNotEmpty proverava da kolekcija nije prazna.
List<Integer> list = new ArrayList<>();
list.add(2);
list.add(1);
list.add(3);
if (CollectionUtils.isEmpty(list)) {
System.out.println("Kolekcija je prazna");
}
if (CollectionUtils.isNotEmpty(list)) {
System.out.println("Kolekcija nije prazna");
}Operacije nad dve kolekcije
Ponekad treba da izvršimo operacije nad dve postojeće kolekcije, na primer presek ili uniju.
List<Integer> list = new ArrayList<>();
list.add(2);
list.add(1);
list.add(3);
List<Integer> list2 = new ArrayList<>();
list2.add(2);
list2.add(4);
// unija
Collection<Integer> unionList = CollectionUtils.union(list, list2);
System.out.println(unionList);
// presek
Collection<Integer> intersectionList = CollectionUtils.intersection(list, list2);
System.out.println(intersectionList);
// komplement preseka
Collection<Integer> disjunctionList = CollectionUtils.disjunction(list, list2);
System.out.println(disjunctionList);
// razlika
Collection<Integer> subtractList = CollectionUtils.subtract(list, list2);
System.out.println(subtractList);Rezultat izvršavanja:
[1, 2, 3, 4]
[2]
[1, 3, 4]
[1, 3]Iskreno, operacije nad dve kolekcije se u praksi prilično često koriste, naročito u mnogim scenarijima obrade u serijama. Ranije smo morali da pišemo gomilu koda, a nije nam palo na pamet da već postoji gotovo rešenje.
07,Rezime
U celosti, Collections alatka, kao glavni domaćin okvira za kolekcije, pruža veoma pogodne metode koje možemo pozivati i koje se lako savladavaju — nema tu nikakvih teškoća; pogled na komentar metode uglavnom je dovoljan da se shvati čemu služi.
Međutim, alat je tu; koristiti ga je jedno, a razumeti zašto se tako koristi je sasvim drugo. Da li ćete podići nivo svog programiranja u velikoj meri zavisi od toga da li ste zašli u izvorni kod i videli kako majstori koji su dizajnirali JDK pišu kod — usvojite li koji trik, brzo ćete se istaći na radnom mestu.
Čini se da su dizajneri JDK-a najbolji učitelji na svetu: dokumentacija ne može detaljnija, kod ne može elegantniji, i uglavnom su dostigli vrhunac performansi.
Neko će možda reći da alatke nisu od neke koristi, da se sve svodi na puko pozivanje metoda, ali to je velika greška: kada bi vi trebalo da je napišete, da li biste stvorili alatku poput Collections?
To je pitanje o kojem bi pravi majstor trebalo da razmišlja.
