Uvod u jOOL

1. Pregled

U ovom ćemo članku pogledati jOOLknjižnica - još jedan proizvod od jOOQ.

2. Ovisnost Mavena

Počnimo s dodavanjem Mavenove ovisnosti na svoj pom.xml:

 org.jooq jool 0.9.12 

Najnoviju verziju možete pronaći ovdje.

3. Funkcionalna sučelja

U Javi 8, funkcionalna sučelja prilično su ograničena. Prihvaćaju maksimalan broj dva parametra i nemaju mnogo dodatnih značajki.

jOOL to popravlja dokazujući skup novih funkcionalnih sučelja koja mogu prihvatiti čak 16 parametara (od Funkcija1 do Funkcija16) a obogaćeni su dodatnim praktičnim metodama.

Na primjer, za stvaranje funkcije koja uzima tri argumenta možemo koristiti Funkcija3:

Funkcija3 lengthSum = (v1, v2, v3) -> v1.length () + v2.length () + v3.length ();

U čistoj Javi trebali biste ga sami implementirati. Osim toga, funkcionalna sučelja iz jOOL-a imaju metodu applyPartial () koji nam omogućuje da djelomično nanošenje izvedemo lako:

Funkcija2 addTwoNumbers = (v1, v2) -> v1 + v2; Funkcija1 addToTwo = addTwoNumbers.applyPartial (2); Cjelobrojni rezultat = addToTwo.apply (5); assertEquals (rezultat, (Integer) 7);

Kada imamo metodu koja je od Funkcija2 tipa, možemo ga lako transformirati u standardnu ​​Javu BiFunction pomoću a toBiFunction () metoda:

BiFunction biFunc = addTwoNumbers.toBiFunction ();

Slično tome, postoji funkcionirati() metoda u Funkcija1 tip.

4. Korijeni

Tuple je vrlo važan konstrukt u svijetu funkcionalnog programiranja. To je tipizirani spremnik za vrijednosti u kojima svaka vrijednost može imati drugačiji tip. Korijeni se često koriste kao argumenti funkcije.

Također su vrlo korisni kada rade transformacije u toku događaja. U jOOL-u imamo korpice koje mogu umotati od jedne do šesnaest vrijednosti koje pruža Korijen1 do Korijen16 vrste:

korijen (2, 2)

I za četiri vrijednosti:

korijen (1,2,3,4); 

Razmotrimo primjer kada imamo niz korijena koji su nosili 3 vrijednosti:

Sljedeće personDetails = Seq.of (korpica ("michael", "slično", 49), korpica ("jodie", "varijabla", 43)); Korpica2 korpica = korpica ("zima", "ljeto"); Popis rezultat = personDetails .map (t -> t.limit2 (). concat (tuple)). toList (); assertEquals (rezultat, Arrays.asList (tuple ("michael", "slično", "zima", "ljeto"), tuple ("jodie", "varijabla", "zima", "ljeto")));

Na korijenima možemo koristiti različite vrste transformacija. Prvo, nazivamo a limit2 () metoda za preuzimanje samo dvije vrijednosti Korijen3. Zatim, zovemo a concat () metoda za spajanje dviju korpica.

Kao rezultat dobivamo vrijednosti koje imaju vrijednost a Korijen4 tip.

5. Sljedeće

The Sljedeće konstrukcija dodaje metode više razine na a Stream dok često koristi svoje metode ispod.

5.1. Sadrži operacije

Možemo pronaći nekoliko varijanti metoda koje provjeravaju prisutnost elemenata u a Sljedeće Neke od tih metoda koriste anyMatch () metoda iz a Stream razred:

assertTrue (Dalje (1, 2, 3, 4) .sadrži (2)); assertTrue (Seq.of (1, 2, 3, 4) .containsAll (2, 3)); assertTrue (Seq.of (1, 2, 3, 4) .containsAny (2, 5)); 

5.2. Pridružite se operacijama

Kada imamo dva toka i želimo im se pridružiti (slično operaciji SQL pridruživanja dvaju skupova podataka), koristeći standardni Stream razred nije baš elegantan način da se to učini:

Lijevi tok = Stream.of (1, 2, 4); Struja desno = Stream.of (1, 2, 3); Popis rightCollected = right.collect (Collectors.toList ()); Popis collect = left .filter (rightCollected :: contains) .collect (Collectors.toList ()); assertEquals (collect, Arrays.asList (1, 2));

Moramo prikupiti pravo stream na popis, kako bi se spriječilo java.lang.IllegalStateException: stream je već operiran ili zatvoren. Dalje, moramo izvršiti operaciju nuspojava pristupanjem a desnoPrikupljeno popis iz a filtar metoda. To je sklonost pogreškama i nije elegantan način spajanja dvaju skupova podataka.

Srećom,Sljedeće ima korisne metode za spajanje unutarnjeg, lijevog i desnog skupa podataka. Te metode skrivaju implementaciju koja izlaže elegantni API.

Unutarnje spajanje možemo napraviti pomoću innerJoin () metoda:

assertEquals (Seq.of (1, 2, 4) .innerJoin (Seq.of (1, 2, 3), (a, b) -> a == b) .toList (), Arrays.asList (tuple (1 , 1), korijen (2, 2)));

U skladu s tim možemo napraviti spajanja udesno i ulijevo:

assertEquals (Seq.of (1, 2, 4) .leftOuterJoin (Seq.of (1, 2, 3), (a, b) -> a == b) .toList (), Arrays.asList (tuple (1 , 1), nabor (2, 2), nabor (4, null))); assertEquals (Seq.of (1, 2, 4) .rightOuterJoin (Seq.of (1, 2, 3), (a, b) -> a == b) .toList (), Arrays.asList (tuple (1 , 1), nabor (2, 2), nabor (null, 3)));

Postoji čak i crossJoin () metoda koja omogućuje kartezijansko spajanje dvaju skupova podataka:

assertEquals (Seq.of (1, 2) .crossJoin (Seq.of ("A", "B")). toList (), Arrays.asList (tuple (1, "A"), tuple (1, "B "), korice (2," A "), korice (2," B ")));

5.3. Manipuliranje a Sljedeće

Sljedeće ima mnogo korisnih metoda za manipulaciju sekvencama elemenata. Pogledajmo neke od njih.

Možemo koristiti a ciklus() metoda za višekratno uzimanje elemenata iz izvorne sekvence. Stvorit će beskonačan tok, pa moramo biti oprezni pri prikupljanju rezultata na popisu, stoga moramo koristiti ograničiti() metoda za pretvaranje beskonačnog niza u konačni:

assertEquals (Seq.of (1, 2, 3) .cycle (). limit (9) .toList (), Arrays.asList (1, 2, 3, 1, 2, 3, 1, 2, 3));

Recimo da želimo duplicirati sve elemente iz jedne sekvence u drugu sekvencu. The duplikat() metoda čini upravo to:

assertEquals (Seq.of (1, 2, 3) .duplicate (). map ((first, second) -> tuple (first.toList (), second.toList ())), tuple (Arrays.asList (1, 2, 3), Arrays.asList (1, 2, 3))); 

Vraćajući se tip a duplikat() metoda je skup od dvije sekvence.

Recimo da imamo niz cijelih brojeva i želimo taj niz podijeliti u dva niza pomoću nekog predikata. Možemo koristiti a particija () metoda:

assertEquals (Seq.of (1, 2, 3, 4) .partition (i -> i> 2) .map ((first, second) -> tuple (first.toList (), second.toList ())), korijen (Arrays.asList (3, 4), Arrays.asList (1, 2)));

5.4. Grupiranje elemenata

Grupiranje elemenata pomoću ključa pomoću Stream API je glomazan i neintuitivan - jer ga moramo koristiti prikupiti() metoda s a Kolekcionari.grupiranjeBy kolektor.

Sljedeće skriva taj kod iza groupBy () metoda koja se vraća Karta pa nema potrebe koristiti a prikupiti() metoda izričito:

Karta očekujeAfterGroupBy = novi HashMap (); očekuje seAfterGroupBy.put (1, Arrays.asList (1, 3)); očekuje seAfterGroupBy.put (0, Arrays.asList (2, 4)); assertEquals (Seq.of (1, 2, 3, 4) .groupBy (i -> i% 2), očekujeAfterGroupBy);

5.5. Preskakanje elemenata

Recimo da imamo niz elemenata i želimo preskočiti elemente dok se predikat ne podudara. Kada je predikat zadovoljen, elementi bi trebali sletjeti u rezultirajućem nizu.

Možemo koristiti a preskočiDok () metoda za to:

assertEquals (Seq.of (1, 2, 3, 4, 5) .skipWhile (i -> i <3) .toList (), Arrays.asList (3, 4, 5));

Isti rezultat možemo postići pomoću a skipUntil () metoda:

assertEquals (Seq.of (1, 2, 3, 4, 5) .skipUntil (i -> i == 3) .toList (), Arrays.asList (3, 4, 5));

5.6. Zipping sekvence

Kada obrađujemo sekvence elemenata, često postoji potreba da se oni stisnu u jedan slijed.

The ZIP () API koji se može koristiti za spajanje dvije sekvence u jednu:

assertEquals (Seq.of (1, 2, 3) .zip (Seq.of ("a", "b", "c")). toList (), Arrays.asList (tuple (1, "a"), korijen (2, "b"), korijen (3, "c")));

Rezultirajući slijed sadrži korpe od dva elementa.

Kada komprimiramo dvije sekvence, ali želimo ih komprimirati na specifičan način, možemo proslijediti a BiFunction do a ZIP () metoda koja definira način arhiviranja elemenata:

assertEquals (Seq.of (1, 2, 3) .zip (Seq.of ("a", "b", "c"), (x, y) -> x + ":" + y) .toList ( ), Arrays.asList ("1: a", "2: b", "3: c"));

Ponekad je korisno zipovati sekvencu s indeksom elemenata u ovoj sekvenci putem zipWithIndex () API:

assertEquals (Seq.of ("a", "b", "c"). zipWithIndex (). toList (), Arrays.asList (tuple ("a", 0L), tuple ("b", 1L), tuple ("c", 2L)));

6. Pretvaranje provjerenih iznimki u neprovjerene

Recimo da imamo metodu koja uzima niz i može baciti provjerenu iznimku:

public Integer methodThatThrowsChecked (String arg) baca Exception {return arg.length (); }

Zatim želimo mapirati elemente a Stream primjenjujući tu metodu na svaki element. Ne postoji način da se ta iznimka riješi više pa je trebamo riješiti s tom iznimkom u a karta() metoda:

Popis collect = Stream.of ("a", "b", "c"). Map (elem -> {try {return methodThatThrowsChecked (elem);} catch (Iznimka e) {e.printStackTrace (); baciti novi RuntimeException (e);}}). collect (Collectors.toList ()); assertEquals (collect, Arrays.asList (1, 1, 1));

S tom iznimkom ne možemo puno učiniti zbog dizajna funkcionalnih sučelja u Javi, pa u klauzuli klauzule pretvaramo provjerenu iznimku u neprovjerenu.

Srećom, u jOOL-u postoji Neoznačeno klasa koja ima metode koje mogu pretvoriti provjerene iznimke u neprovjerene iznimke:

Popis collect = Stream.of ("a", "b", "c") .map (Nekontrolirana.funkcija (elem -> methodThatrowshhecked (elem))) .collect (Collectors.toList ()); assertEquals (collect, Arrays.asList (1, 1, 1));

Obavljamo poziv na methodThatThrowsChecked () u an Neoznačeno.funkcija () metoda koja obrađuje pretvaranje iznimaka ispod.

7. Zaključak

Ovaj članak pokazuje kako se koristi jOOL knjižnica koja dodaje korisne dodatne metode u Java standard Stream API.

Provedbu svih ovih primjera i isječaka koda možete pronaći u projektu GitHub - ovo je Maven projekt, pa bi ga trebalo lako uvesti i pokrenuti kakav jest.