Introduktion til Atlassian Fugue

1. Introduktion

Fugue er et Java-bibliotek af Atlassian; det er en samling hjælpeprogrammer, der understøtter Funktionel programmering.

I denne opskrivning vil vi fokusere på og udforske de vigtigste Fugues API'er.

2. Kom godt i gang med fuga

For at begynde at bruge Fugue i vores projekter skal vi tilføje følgende afhængighed:

 io.atlassian.fugue fugue 4.5.1 

Vi kan finde den nyeste version af Fugue over på Maven Central.

3. Mulighed

Lad os starte vores rejse med at se på Mulighed klasse, som er Fuga's svar på java.util. Valgfrit.

Som vi kan gætte efter navnet, Mulighed's en container, der repræsenterer en potentielt fraværende værdi.

Med andre ord, en Mulighed er enten Nogle værdi af en bestemt type eller Ingen:

Option none = Option.none (); assertFalse (none.isDefined ()); Option nogle = Option.some ("værdi"); assertTrue (some.isDefined ()); assertEquals ("værdi", some.get ()); Option måske = Option.option (someInputValue);

3.1. Det kort Operation

En af de almindelige funktionelle programmerings-API'er er kort() metode, der gør det muligt at anvende en forudsat funktion på underliggende elementer.

Metoden anvender den leverede funktion til Mulighed'S værdi, hvis den er til stede:

Option nogle = Option.some ("værdi") .map (String :: toUpperCase); assertEquals ("VALUE", some.get ());

3.2. Mulighed og en Nul Værdi

Udover navngivningsforskelle foretog Atlassian et par designvalg til Mulighed der adskiller sig fra Valgfri; lad os nu se på dem.

Vi kan ikke direkte oprette en ikke-tom Mulighed holder en nul værdi:

Option.some (null);

Ovenstående giver en undtagelse.

Vi kan dog få en som et resultat af at bruge kort() operation:

Option nogle = Option.some ("værdi") .map (x -> null); assertNull (some.get ());

Dette er ikke muligt, når du bare bruger java.util. valgfri.

3.3. Mulighed Is Iterabel

Mulighed kan behandles som en samling, der indeholder maksimalt et element, så det giver mening at implementere Iterabel interface.

Dette øger interoperabiliteten meget, når du arbejder med samlinger / streams.

Og nu kan for eksempel sammenkædes med en anden samling:

Option nogle = Option.some ("værdi"); Iterable strings = Iterables .concat (nogle, Arrays.asList ("a", "b", "c"));

3.4. Konvertering Mulighed til Strøm

Siden en Mulighed er en Iterabel, det kan konverteres til en Strøm let også.

Efter konvertering er den Strøm forekomst vil have nøjagtigt et element, hvis indstillingen er til stede, eller ellers nul:

assertEquals (0, Option.none (). toStream (). count ()); assertEquals (1, Option.some ("værdi"). tilStream (). count ());

3.5. java.util. Valgfrit Interoperabilitet

Hvis vi har brug for en standard Valgfri implementering, kan vi nemt få det ved hjælp af til valgfrit () metode:

Valgfri valgfri = Option.none () .toOptional (); assertTrue (Option.fromOptional (valgfri) .isEmpty ());

3.6. Det Muligheder Værktøjsklasse

Endelig giver Fugue nogle værktøjsmetoder til at arbejde med Muligheds i det passende navngivne Muligheder klasse.

Det indeholder metoder som f.eks filterIngen til fjernelse af tom Muligheder fra en samling, og flad for turing en samling af Muligheder i en samling af lukkede genstande, der filtreres tomme ud Muligheder.

Derudover har den flere varianter af løfte op metode, der løfter en Fungere ind i en Fungere>:

Funktion f = (Heltal x) -> x> 0? x + 1: null; Fungere løftet = Options.lift (f); assertEquals (2, (lang) løftet. anvend (Option.some (1)). get ()); assertTrue (lifted.apply (Option.none ()). erEmpty ());

Dette er nyttigt, når vi ønsker at videregive en funktion, som ikke er opmærksom på Mulighed til en eller anden metode, der bruger Mulighed.

Bemærk, ligesom kort metode, løfte op kortlægger ikke null til Ingen:

assertEquals (null, lifted.apply (Option.some (0)). get ());

4. Enten til beregninger med to mulige resultater

Som vi har set, Mulighed klasse giver os mulighed for at håndtere fraværet af en værdi på en funktionel måde.

Imidlertid er vi undertiden nødt til at returnere flere oplysninger end "ingen værdi"; for eksempel vil vi måske returnere enten en legitim værdi eller et fejlobjekt.

Det Enten klasse dækker denne brugssag.

En forekomst af Enten kan være en Ret eller a Venstre, men aldrig begge på samme tid.

Efter konvention er højre resultatet af en vellykket beregning, mens venstre er det ekstraordinære tilfælde.

4.1. Konstruktion af en Enten

Vi kan få en Enten eksempel ved at kalde en af ​​de to statiske fabriksmetoder.

Vi ringer ret hvis vi vil have en Enten indeholdende Ret værdi:

Enten ret = Enten.højre ("værdi");

Ellers ringer vi venstre:

Enten venstre = Enten. Venstre (-1);

Her kan vores beregning enten returnere a Snor eller en Heltal.

4.2. Brug af en Enten

Når vi har en Enten For eksempel kan vi kontrollere, om det er venstre eller højre, og handle i overensstemmelse hermed:

hvis (enten.isRight ()) {...}

Mere interessant er, at vi kan kæde operationer ved hjælp af en funktionel stil:

enten .map (String :: toUpperCase) .getOrNull ();

4.3. Fremskrivninger

Det vigtigste, der adskiller sig fra andre monadiske værktøjer som f.eks Mulighed, prøv, er det faktum, at det ofte er upartisk. Kort sagt, hvis vi kalder map () metoden, Enten ved ikke, om jeg skal arbejde med Venstre eller Ret side.

Det er her fremskrivninger er nyttige.

Venstre og højre fremspring er spejlevisninger af en Enten der fokuserer på venstre eller højre værdi, henholdsvis:

either.left () .map (x -> decodeSQLErrorCode (x));

I ovenstående kodestykke, hvis Enten er Venstre, afkodeSQLErrorCode () bliver anvendt på det underliggende element. Hvis Enten er Ret, det gør det ikke. Samme omvendt, når du bruger den rigtige fremspring.

4.4. Hjælpemetoder

Som med Muligheder, Fugue tilbyder en klasse fuld af hjælpeprogrammer til Eithers, så godt, og det hedder bare sådan: Eithers.

Den indeholder metoder til filtrering, casting og iterering over samlinger af Entens.

5. Undtagelse Håndtering med Prøve

Vi afslutter vores rundvisning i enten denne eller den datatype i Fuga med en anden variant kaldet Prøve.

Prøve ligner Enten, men det adskiller sig ved, at det er dedikeret til at arbejde med undtagelser.

Synes godt om Mulighed og i modsætning til Enten, Prøve parametriseres over en enkelt type, fordi den "anden" type er fastgjort til Undtagelse (mens for Mulighed det er implicit Ugyldig).

Så, en Prøve kan enten være en Succes eller a Fiasko:

assertTrue (Try.failure (ny undtagelse ("Fail!")). isFailure ()); assertTrue (Try.successful ("OK"). isSuccess ());

5.1. Instantiering af en Prøve

Ofte opretter vi ikke en Prøve eksplicit som en succes eller en fiasko; snarere opretter vi en fra et metodekald.

Kontrolleret. Af kalder en given funktion og returnerer a Prøve indkapsler dens returværdi eller enhver kastet undtagelse:

assertTrue (Checked.of (() -> "ok"). isSuccess ()); assertTrue (Checked.of (() -> {throw new Exception ("ko");}). isFailure ());

En anden metode, Kontrolleret. Løft, tager en potentiel kastefunktion og elevatorer det til en funktion, der returnerer en Prøve:

Checked.Function throwException = (String x) -> {throw new Exception (x); }; assertTrue (Checked.lift (throwException) .apply ("ko"). isFailure ());

5.2. Arbejder med Prøve

Når vi har en Prøve, de tre mest almindelige ting, vi måske i sidste ende vil gøre med det, er:

  1. udtrækning af dens værdi
  2. kæde nogle operationer til den vellykkede værdi
  3. håndtering af undtagelsen med en funktion

Desuden bortskaffes naturligvis Prøve eller videregive det til andre metoder, er ovenstående tre ikke de eneste muligheder, vi har, men alle de andre indbyggede metoder er bare en bekvemmelighed i forhold til disse tre.

5.3. Henter den vellykkede værdi

For at udtrække værdien bruger vi getOrElse metode:

assertEquals (42, failedTry.getOrElse (() -> 42));

Den returnerer den vellykkede værdi, hvis den er til stede, eller en anden beregnet værdi ellers.

Der er ingen getOrThrow eller lignende, men siden getOrElse fanger ingen undtagelse, vi kan nemt skrive det:

someTry.getOrElse (() -> {kast nyt NoSuchElementException ("Intet at få");});

5.4. Kædekald efter succes

I en funktionel stil kan vi anvende en funktion til succesværdien (hvis den findes) uden først at udtrække den eksplicit.

Dette er det typiske kort metode, vi finder i Mulighed, Enten og de fleste andre containere og samlinger:

Prøv aTry = Try.successful (42) .map (x -> x + 1);

Det returnerer en Prøve så vi kan kæde yderligere operationer.

Selvfølgelig har vi også flatMap bred vifte:

Try.successful (42) .flatMap (x -> Try.successful (x + 1));

5.5. Gendannelse fra undtagelser

Vi har analoge kortlægningsoperationer, der fungerer med undtagelse af a Prøve (hvis til stede) snarere end dens vellykkede værdi.

Disse metoder adskiller sig imidlertid ved, at deres betydning er at komme sig fra undtagelsen, dvs. producere en succes Prøve i standardtilfælde.

Således kan vi producere en ny værdi med gendanne:

Prøv at gendanne = Prøv. Fejl (ny undtagelse ("boo!")). Genopretning ((undtagelse e) -> e.getMessage () + "gendannet."); assertTrue (recover.isSuccess ()); assertEquals ("boo! recovered.", recover.getOrElse (() -> null));

Som vi kan se, tager gendannelsesfunktionen undtagelsen som sit eneste argument.

Hvis gendannelsesfunktionen i sig selv kaster, er resultatet en anden mislykket Prøve:

Prøv fiasko = Try.failure (ny undtagelse ("boo!")). Gendan (x -> {kast ny RuntimeException (x);}); assertTrue (failure.isFailure ());

Den analoge til flatMap Hedder komme sig med:

Prøv at gendanne = Prøv. Fejl (ny undtagelse ("boo!")) .RecoverWith ((undtagelse e) -> Try.successful ("gendannet igen!")); assertTrue (recover.isSuccess ()); assertEquals ("gendannet igen!", recover.getOrElse (() -> null));

6. Andre hjælpeprogrammer

Lad os nu se hurtigt på nogle af de andre hjælpeprogrammer i Fugue, inden vi pakker det ind.

6.1. Par

EN Par er en virkelig enkel og alsidig datastruktur, der er lavet af to lige så vigtige komponenter, som Fugue kalder venstre og ret:

Parpar = Par.par (1, "a"); assertEquals (1, (int) pair.left ()); assertEquals ("a", pair.right ());

Fuga giver ikke mange indbyggede metoder til Pars, udover kortlægning og det applikative funktormønster.

Imidlertid, Pars bruges i hele biblioteket, og de er let tilgængelige til brugerprogrammer.

Den næste fattige persons implementering af Lisp er kun et par tastetryk væk!

6.2. Enhed

Enhed er en enum med en enkelt værdi, der skal repræsentere "ingen værdi".

Det er en erstatning for ugyldig returneringstype og Ugyldig klasse, der fjerner nul:

Enhed doSomething () {System.out.println ("Hej! Bivirkning"); retur enhed (); }

Ganske overraskende dog Mulighed forstår ikke Enhed, behandler det som en værdi i stedet for ingen.

6.3. Statiske hjælpeprogrammer

Vi har et par klasser fyldt med statiske hjælpemetoder, som vi ikke behøver at skrive og teste.

Det Funktioner klasse tilbyder metoder, der bruger og transformerer funktioner på forskellige måder: komposition, anvendelse, curry, delvise funktioner ved hjælp af Mulighed, svag memoisering osv.

Det Leverandører klasse giver en lignende, men mere begrænset samling af hjælpeprogrammer til Leverandørs, det vil sige funktioner uden argumenter.

Iterables og Iteratorerendelig indeholder en række statiske metoder til at manipulere de to almindeligt anvendte standard Java-grænseflader.

7. Konklusion

I denne artikel har vi givet et overblik over Fugue-biblioteket af Atlassian.

Vi har ikke rørt de algebra-tunge klasser som Monoid og Semigroups fordi de ikke passer ind i en generalistartikel.

Du kan dog læse om dem og mere i Fugue-javadocs og kildekode.

Vi har heller ikke rørt nogen af ​​de valgfri moduler, der f.eks. Tilbyder integrationer med Guava og Scala.

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.


$config[zx-auto] not found$config[zx-overlay] not found