Introduksjon til jOOL

1. Oversikt

I denne artikkelen vil vi se på jOOLbibliotek - et annet produkt fra jOOQ.

2. Maven avhengighet

La oss starte med å legge til en Maven-avhengighet til din pom.xml:

 org.jooq jool 0.9.12 

Du finner den siste versjonen her.

3. Funksjonelle grensesnitt

I Java 8 er funksjonelle grensesnitt ganske begrensede. De godtar maksimalt antall to parametere og har ikke mange tilleggsfunksjoner.

jOOL løser det ved å bevise et sett med nye funksjonelle grensesnitt som kan akseptere til og med 16 parametere (fra Funksjon 1 opp til Funksjon16) og er beriket med flere praktiske metoder.

For eksempel, for å lage en funksjon som tar tre argumenter, kan vi bruke Funksjon3:

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

I ren Java trenger du å implementere det selv. I tillegg til at funksjonelle grensesnitt fra jOOL har en metode gjelder delvis () som lar oss enkelt utføre en delvis applikasjon:

Funksjon2 addTwoNumbers = (v1, v2) -> v1 + v2; Funksjon1 addToTwo = addTwoNumbers.applyPartially (2); Heltalsresultat = addToTwo.apply (5); assertEquals (resultat, (Heltall) 7);

Når vi har en metode som er av en Funksjon 2 type, kan vi enkelt transformere det til en standard Java BiFunction ved å bruke en toBiFunction () metode:

BiFunction biFunc = addTwoNumbers.toBiFunction ();

Tilsvarende er det en å fungere() metode i Funksjon 1 type.

4. Tuples

En tuple er en veldig viktig konstruksjon i en funksjonell programmeringsverden. Det er en skrevet beholder for verdier der hver verdi kan ha en annen type. Tuples brukes ofte som funksjonsargumenter.

De er også veldig nyttige når du gjør transformasjoner på en strøm av hendelser. I jOOL har vi tupler som kan pakke fra en opp til seksten verdier, levert av Tuple1 opp til Tuple16 typer:

tuple (2, 2)

Og for fire verdier:

tupel (1,2,3,4); 

La oss se på et eksempel når vi har en sekvens med tupler som hadde 3 verdier:

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

Vi kan bruke forskjellige typer transformasjoner på tuplene. Først kaller vi a limit2 () metode for å ta bare to verdier fra Tuple3. Så kaller vi en concat () metode for å sammenkoble to tupler.

I resultatet får vi verdier som er av a Tuple4 type.

5. Sekv

De Sekv konstruere legger til høyere nivå metoder på en Strøm mens ofte bruker metodene under.

5.1. Inneholder operasjoner

Vi kan finne et par varianter av metoder for å sjekke om det er elementer i en Sekv. Noen av disse metodene bruker 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. Bli med i Operasjoner

Når vi har to strømmer og vi vil bli med dem (ligner på en SQL-sammenkobling av to datasett), ved hjelp av en standard Strøm klasse er ikke en veldig elegant måte å gjøre dette på:

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

Vi må samle inn Ikke sant strøm til en liste, for å forhindre java.lang.IllegalStateException: strømmen er allerede operert eller stengt. Deretter må vi gjøre en bivirkningsoperasjon ved å få tilgang til a rightCollected liste fra en filter metode. Det er feil utsatt og ikke elegant måte å bli med i to datasett.

Heldigvis,Sekv har nyttige metoder for å gjøre indre, venstre og høyre sammenføyning på datasett. Disse metodene skjuler en implementering av det som avslører elegant API.

Vi kan gjøre en indre sammenføyning ved å bruke 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 gjøre høyre og venstre sammenføyning tilsvarende:

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

Det er til og med en crossJoin () metode som gjør det mulig å lage en kartesisk sammenføyning av to datasett:

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. Manipulere en Sekv

Sekv har mange nyttige metoder for å manipulere sekvenser av elementer. La oss se på noen av dem.

Vi kan bruke en syklus() metode for å ta flere ganger elementer fra en kildesekvens. Det vil skape en uendelig strøm, så vi må være forsiktige når vi samler inn resultater til en liste, så vi må bruke en grense() metode for å transformere uendelig rekkefølge til endelig:

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

La oss si at vi vil duplisere alle elementene fra en sekvens til den andre sekvensen. De duplisere() metoden gjør akkurat 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))); 

Returnerende type a duplisere() metoden er en tuple av to sekvenser.

La oss si at vi har en sekvens av heltall, og vi vil dele den sekvensen i to sekvenser ved hjelp av noe predikat. Vi kan bruke en skillevegg() metode:

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

5.4. Gruppering av elementer

Gruppere elementer etter en nøkkel ved hjelp av Strøm API er tungvint og ikke-intuitivt - fordi vi trenger å bruke samle inn() metode med en Collectors.groupingBy samler.

Sekv skjuler den koden bak en gruppe av() metode som returnerer Kart så det er ikke nødvendig å bruke en samle inn() metoden eksplisitt:

Kart 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. Hopp over elementer

La oss si at vi har en sekvens av elementer, og vi vil hoppe over elementer mens et predikat ikke samsvarer. Når et predikat er oppfylt, skal elementene lande i en resulterende sekvens.

Vi kan bruke en skipWhile () metode for det:

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

Vi kan oppnå det samme resultatet ved hjelp av a skipUntil () metode:

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

5.6. Zipping Sekvenser

Når vi behandler sekvenser av elementer, er det ofte behov for å pakke dem inn i en sekvens.

De glidelås() API som kan brukes til å pakke to sekvenser til 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 sekvensen inneholder tupler av to elementer.

Når vi zipper to sekvenser, men vi vil zip dem på en bestemt måte kan vi passere en BiFunction til en glidelås() metode som definerer måten å zippe elementer på:

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

Noen ganger er det nyttig å zip sekvens med en indeks over elementer i denne sekvensen, via zipWithIndex () API:

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

6. Konvertere avmerkede unntak til ukontrollert

La oss si at vi har en metode som tar en streng og kan kaste et avkrysset unntak:

public Integer methodThatThrowsChecked (String arg) kaster Unntak {return arg.length (); }

Da vil vi kartlegge elementer av en Strøm bruke den metoden på hvert element. Det er ingen måte å håndtere det unntaket høyere, så vi må håndtere det unntaket i en kart() metode:

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

Det er ikke mye vi kan gjøre med det unntaket på grunn av utformingen av funksjonelle grensesnitt i Java, så i en fangstklausul konverterer vi et avkrysset unntak til ukontrollert.

Heldigvis er det i en jOL Ukontrollert klasse som har metoder som kan konvertere avmerkede unntak til ukontrollerte unntak:

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

Vi pakker inn en samtale til en methodThatThrowsChecked () inn i en Unchecked.function () metode som håndterer konvertering av unntak under.

7. Konklusjon

Denne artikkelen viser hvordan du bruker jOOL-biblioteket som gir nyttige tilleggsmetoder til Java-standarden Strøm API.

Implementeringen av alle disse eksemplene og kodebitene finnes i GitHub-prosjektet - dette er et Maven-prosjekt, så det skal være enkelt å importere og kjøre som det er.