A Java 8 újdonságai

Stream

Bevezetés

Nézzük meg, hogy milyen újításokat hozott a Collections API.

A leginkább említésre méltó újdonság az a Stream API. Ezt minden Java collectionon tudjuk használni, mivel a Collection interéfsz megköveteli az ehhez tartozó metódust.

Akármilyen Collection osztályból létre tudunk hozni egy úgynevezett streamet. Ezt leginkább úgy lehet elképzelni, hogy ez a stream kezdetben az összes elemét tartalmazza a collectionnek, majd ezen a Stream objektumon végezhetjük el a különböző műveleteinket. Egy fontos dolog, hogy a streameknek két fajtájuk van: parallel, sequential. Ahogy a nevük is mutatja, a parallel egy párhuzamos feldolgozást végez, míg a sequential egy szekvenciálist. Ahhoz, hogy a stream melyik fajtáját akarjuk használni, egy parallel(), vagy egy sequential() metódust kell hívnunk a streamen. Ha teljesen mindegy nekünk, hogy milyen streamet használunk, akkor csak egy sima stream() hívás elég az adott konténeren. Ahhoz, hogy ezt a streamet, újra valami használható collectionbe rakjuk, Collectorokat kell használnunk.

A Collectorok segítségével a streamet betölthetjük egy collectionbe, mint például List, Map, stb. Szerencsére nem kell megírnunk nekünk ezeket, mivel a Java fejlesztői már rengeteg Collectort implementáltak nekünk, így egy metódushívással tudunk egy stream objektumot belepakolni egy Listbe, akár Mapbe, akár Set-be.

collect

Ahogy a bevezetésben említettem, Collectorokat kell használnunk, hogy egz collectionbe betöltsünk egy adott streamet. Hogy ezt megtegyük, egy collect metódust kell meghívnunk a stream objektumon, majd ennek a collect metódusnak kell átadni egy Collectort. A Java 8 által nyújtott Collectorokat a Collectors osztály tartalmazza.

Nézzünk erre egy példát.

List list = new ArrayList<>(); //lista feltöltése List stringList = list.stream().collect(Collectors.toList());
Ebben a példában a listával az nem csinálunk semmit az ég világon, csak lemásoljuk.

map

Nézzük meg a streameken hívható map() metódust. A map metódus egy a streamben levő típusról "mappel" egy másik típusra. A másik típus jelentheti ugyanazt természetesen.

Például gondoljunk bele, hogy van egy Stringeket tartalmazó listánk, és az összes Stringnek, a nagybetűs megfelelőjéből akarunk egy listát. Java 8 előtt ezt csináltuk volna:

List collected = new ArrayList<>(); for(String s : Arrays.asList("a", "b", "hello")) { String upperS = s.toUpperCase(); collected.add(upperS); }

A Stream API-t használva viszont így csinálhatjuk:

List collected = Stream.of("a", "b", "hello").map(s -> s.toUpperCase()).collect(Collectors.toList());

filter

A filter() metódus az elemek szűrésére való.

Így tudtunk Java 8 előtt minden olyan elemet kiválasztani egy listából, ami 'a' betűvel kezdődik:

List collected = new ArrayList<>(); for(String s : Arrays.asList("a", "b", "hello")) { if(s.startsWith("a")) collected.add(s); }

Java 8-at használva már megtehetjük ezt:

List collected = Stream.of("a", "b", "hello").filter(s -> s.startsWith("a")).collect(Collectors.toList());
Nézzük csak meg a két példa olvashatóságát. A Stream API-t használva egyértelműen egyszerűsödött a kódunk. Ami megfontosabb, hogy a ciklussal történő implementáció szekvenciális. A Stream API-t használó változat pedig párhuzamos feldolgozást is lehetővé tesz, így sokkal gyorsabban megtörténhet a szűrés.

max-min

Egy nagyon általános programozás szintén, hogy ki akarjuk választani a lista legnagyobb/legkisebb elemét valamilyen attribútum szerint. Erre használható a max() és min() metódus.

Régebben, ugyanúgy mint a korábbi példákban, végig kellett egyesével iterálni a lista elemein, majd kiválasztani a maximálisat.

A Java 8 által elérhető max függvényt használva pedig csinálhatjuk ezt:

List dateList = new ArrayList<>(); //lista feltöltése Date maxDate = dateList.max(Comparator.comparing(d -> d.getTime())).collect(Collectors.toList());
A példában látható, hogy a getTime() metódus alapján válaszjuk ki a maximumot.