Introduktion til jOOL

1. Oversigt

I denne artikel vil vi se på jOOLbibliotek - et andet produkt fra jOOQ.

2. Maven-afhængighed

Lad os starte med at tilføje en Maven-afhængighed til din pom.xml:

 org.jooq jool 0.9.12 

Du kan finde den nyeste version her.

3. Funktionelle grænseflader

I Java 8 er funktionelle grænseflader ret begrænsede. De accepterer det maksimale antal på to parametre og har ikke mange yderligere funktioner.

jOOL løser det ved at bevise et sæt nye funktionelle grænseflader, der kan acceptere endda 16 parametre (fra Funktion 1 op til Funktion16) og er beriget med yderligere praktiske metoder.

For eksempel, for at oprette en funktion, der tager tre argumenter, kan vi bruge Funktion3:

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

I ren Java skal du selv implementere det. Derudover har funktionelle grænseflader fra jOOL en metode ApplyPartially () der giver os mulighed for let at udføre en delvis applikation:

Funktion2 addTwoNumbers = (v1, v2) -> v1 + v2; Funktion1 addToTwo = addTwoNumbers.applyPartially (2); Heltalsresultat = addToTwo.apply (5); assertEquals (resultat, (heltal) 7);

Når vi har en metode, der er af en Funktion2 type, kan vi nemt omdanne det til en standard Java BiFunction ved hjælp af en toBiFunction () metode:

BiFunction biFunc = addTwoNumbers.toBiFunction ();

Tilsvarende er der en at fungere() metode i Funktion 1 type.

4. Tuples

En tuple er en meget vigtig konstruktion i en funktionel programmeringsverden. Det er en indtastet beholder til værdier, hvor hver værdi kan have en anden type. Tuples bruges ofte som funktionsargumenter.

De er også meget nyttige, når du foretager transformationer i en strøm af begivenheder. I jOOL har vi tupler, der kan pakke fra en op til seksten værdier, leveret af Tuple1 op til Tuple16 typer:

tuple (2, 2)

Og for fire værdier:

tupel (1,2,3,4); 

Lad os overveje et eksempel, når vi har en sekvens af tupler, der bar 3 værdier:

Sekv personDetails = Seq.of (tuple ("michael", "similar", 49), tuple ("jodie", "variable", 43)); Tuple2 tuple = tuple ("vinter", "sommer"); Liste resultat = personDetails .map (t -> t.limit2 (). concat (tuple)). toList (); assertEquals (resultat, Arrays.asList (tuple ("michael", "ens", "vinter", "sommer"), tuple ("jodie", "variabel", "vinter", "sommer"));

Vi kan bruge forskellige former for transformation på tupler. Først kalder vi en grænse2 () metode til kun at tage to værdier fra Tuple3. Derefter kalder vi en concat () metode til sammenkædning af to tupler.

I resultatet får vi værdier, der er af a Tuple4 type.

5. Sekv

Det Sekv konstruktion tilføjer metoder på højere niveau på en Strøm mens det ofte bruger sine metoder nedenunder.

5.1. Indeholder operationer

Vi kan finde et par varianter af metoder, der kontrollerer for tilstedeværelsen af ​​elementer i en Sekv. Nogle af disse metoder bruger en anyMatch () metode fra en Strøm klasse:

assertTrue (Seq.of (1, 2, 3, 4) .contains (2)); assertTrue (Seq.of (1, 2, 3, 4) .containsAll (2, 3)); assertTrue (Seq.of (1, 2, 3, 4) .containsAny (2, 5)); 

5.2. Deltag i operationer

Når vi har to streams, og vi vil slutte os til dem (svarende til en SQL-sammenkædning af to datasæt) ved hjælp af en standard Strøm klasse er ikke en meget elegant måde at gøre dette på:

Stream venstre = Stream.of (1, 2, 4); Stream til højre = Stream.of (1, 2, 3); Liste rightCollected = right.collect (Collectors.toList ()); List collect = left .filter (rightCollected :: indeholder) .collect (Collectors.toList ()); assertEquals (indsamle, Arrays.asList (1, 2));

Vi er nødt til at indsamle ret streame til en liste for at forhindre java.lang.IllegalStateException: stream er allerede blevet betjent eller lukket. Dernæst er vi nødt til at foretage en bivirkning ved at få adgang til en rightCollected liste fra en filter metode. Det er en fejlbehæftet og ikke elegant måde at slutte sig til to datasæt på.

Heldigvis,Sekv har nyttige metoder til at gøre indre, venstre og højre sammenføjninger på datasæt. Disse metoder skjuler en implementering af det, der udsætter elegant API.

Vi kan gøre en indre sammenføjning ved at bruge en innerJoin () metode:

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

Vi kan gøre højre og venstre sammenføjninger i overensstemmelse hermed:

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

Der er endda en crossJoin () metode, der gør det muligt at lave en kartesisk sammenføjning af to datasæt:

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

5.3. Manipulering af en Sekv

Sekv har mange nyttige metoder til at manipulere sekvenser af elementer. Lad os se på nogle af dem.

Vi kan bruge en cyklus() metode til gentagne gange at tage elementer fra en kildesekvens. Det vil skabe en uendelig strøm, så vi skal være forsigtige, når vi indsamler resultater til en liste, så vi skal bruge en begrænse() metode til at omdanne uendelig sekvens til endelig:

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

Lad os sige, at vi vil duplikere alle elementer fra en sekvens til den anden sekvens. Det duplikere() metode gør nøjagtigt det:

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))); 

Tilbagevendende type a duplikere() metode er en tuple af to sekvenser.

Lad os sige, at vi har en sekvens af heltal, og vi vil opdele denne sekvens i to sekvenser ved hjælp af et eller andet predikat. Vi kan bruge en skillevæg() metode:

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

5.4. Gruppering af elementer

Gruppering af elementer efter en nøgle ved hjælp af Strøm API er besværligt og ikke-intuitivt - fordi vi har brug for det indsamle() metode med en Collectors.groupingBy samler.

Sekv skjuler den kode bag a groupBy () metode, der vender tilbage Kort så der er ingen grund til at bruge en indsamle() metode eksplicit:

Kort expectAfterGroupBy = ny HashMap (); expectAfterGroupBy.put (1, Arrays.asList (1, 3)); expectAfterGroupBy.put (0, Arrays.asList (2, 4)); assertEquals (Seq.of (1, 2, 3, 4) .groupBy (i -> i% 2), expectedAfterGroupBy);

5.5. Springe over elementer

Lad os sige, at vi har en række af elementer, og vi vil springe over elementer, mens et prædikat ikke matches. Når et prædikat er opfyldt, skal elementerne lande i en resulterende sekvens.

Vi kan bruge en skipWhile () metode til det:

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

Vi kan opnå det samme resultat ved hjælp af en skipUntil () metode:

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

5.6. Lynlåse sekvenser

Når vi behandler sekvenser af elementer, er der ofte behov for at zip dem i en sekvens.

Det lynlås () API, der kunne bruges til at zip to sekvenser i en:

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

Den resulterende sekvens indeholder fordoblinger af to elementer.

Når vi zipper to sekvenser, men vi vil zip dem på en bestemt måde, kan vi videregive en BiFunction til en lynlås () metode, der definerer metoden for lynlåsning af elementer:

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"));

Nogle gange er det nyttigt at zip sekvens med et indeks over elementer i denne sekvens via zipWithIndex () API:

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

6. Konvertering af kontrollerede undtagelser til ikke-markeret

Lad os sige, at vi har en metode, der tager en streng og kan kaste en kontrolleret undtagelse:

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

Så vil vi kortlægge elementer af en Strøm anvende denne metode på hvert element. Der er ingen måde at håndtere denne undtagelse højere på, så vi skal håndtere denne undtagelse i en kort() metode:

List collect = Stream.of ("a", "b", "c"). Map (elem -> {try {return methodThatThrowsChecked (elem);} catch (Undtagelse e) {e.printStackTrace (); smid ny RuntimeException (e);}}). indsamle (Collectors.toList ()); assertEquals (indsamle, Arrays.asList (1, 1, 1));

Der er ikke meget, vi kan gøre med denne undtagelse på grund af designet af funktionelle grænseflader i Java, så i en fangstklausul konverterer vi en afkrydset undtagelse til ukontrolleret.

Heldigvis er der i en jOL en Ikke markeret klasse, der har metoder, der kan konvertere afkrydsede undtagelser til ukontrollerede undtagelser:

List collect = Stream.of ("a", "b", "c") .map (Unchecked.function (elem -> methodThatThrowsChecked (elem))) .collect (Collectors.toList ()); assertEquals (indsamle, Arrays.asList (1, 1, 1));

Vi indpakker et opkald til en methodThatThrowsChecked () ind i en Ikke markeret. Funktion () metode, der håndterer konvertering af undtagelser nedenunder.

7. Konklusion

Denne artikel viser, hvordan du bruger jOOL-biblioteket, der tilføjer nyttige yderligere metoder til Java-standarden Strøm API.

Implementeringen af ​​alle disse eksempler og kodestykker findes i GitHub-projektet - dette er et Maven-projekt, så det skal være let at importere og køre, som det er.