Introduksjon til Atlassian Fugue

1. Introduksjon

Fugue er et Java-bibliotek av Atlassian; det er en samling verktøy som støtter Funksjonell programmering.

I denne oppskriften vil vi fokusere på og utforske de viktigste APIene til Fuga.

2. Komme i gang med fuga

For å begynne å bruke Fugue i prosjektene våre, må vi legge til følgende avhengighet:

 io.atlassian.fugue fugue 4.5.1 

Vi kan finne den nyeste versjonen av Fugue på Maven Central.

3. Alternativ

La oss starte reisen med å se på Alternativ klasse som er Fugues svar på java.util. valgfritt.

Som vi kan gjette etter navnet, Alternativ's en beholder som representerer en potensielt fraværende verdi.

Med andre ord, en Alternativ er enten Noen verdi av en bestemt type eller Ingen:

Alternativ ingen = Alternativ. Ingen (); assertFalse (none.isDefined ()); Alternativ noen = Option.some ("verdi"); assertTrue (some.isDefined ()); assertEquals ("verdi", some.get ()); Alternativ kanskje = Option.option (someInputValue);

3.1. De kart Operasjon

En av de standard funksjonelle programmerings-APIene er kart() metode som gjør det mulig å bruke en gitt funksjon på underliggende elementer.

Metoden bruker den medfølgende funksjonen til AlternativVerdien hvis den er til stede:

Alternativ noen = Option.some ("verdi") .map (String :: toUpperCase); assertEquals ("VALUE", some.get ());

3.2. Alternativ og en Null Verdi

Foruten navneforskjeller, gjorde Atlassian noen designvalg for Alternativ som skiller seg fra Valgfri; la oss nå se på dem.

Vi kan ikke direkte lage et ikke-tomt Alternativ holder en null verdi:

Option.some (null);

Ovennevnte kaster et unntak.

Imidlertid kan vi få en som et resultat av å bruke kart() operasjon:

Alternativ noen = Option.some ("verdi") .map (x -> null); assertNull (some.get ());

Dette er ikke mulig når du bare bruker java.util. valgfritt.

3.3. Alternativ Is Iterabel

Alternativ kan behandles som en samling som inneholder maksimalt ett element, så det er fornuftig for den å implementere Iterabel grensesnitt.

Dette øker interoperabiliteten sterkt når du arbeider med samlinger / strømmer.

Og nå kan for eksempel sammenkobles med en annen samling:

Alternativ noen = Option.some ("verdi"); Iterable strings = Iterables .concat (noen, Arrays.asList ("a", "b", "c"));

3.4. Konvertering Alternativ til Strøm

Siden en Alternativ er en Iterabel, den kan konverteres til en Strøm lett også.

Etter konvertering, vil Strøm forekomst vil ha nøyaktig ett element hvis alternativet er til stede, eller null ellers:

assertEquals (0, Option.none (). toStream (). count ()); assertEquals (1, Option.some ("value"). toStream (). count ());

3.5. java.util. valgfritt Interoperabilitet

Hvis vi trenger en standard Valgfri implementering, kan vi enkelt skaffe det ved hjelp av til Valgfritt () metode:

Valgfritt valgfritt = Alternativ. Ingen (). Til Valgfritt (); assertTrue (Option.fromOptional (valgfritt) .isEmpty ());

3.6. De Alternativer Utility Class

Til slutt gir Fugue noen verktøy for å jobbe med Alternativs i passende navn Alternativer klasse.

Den har metoder som filterIngen for å fjerne tom Alternativer fra en samling, og flate ut for turing en samling av Alternativer i en samling med lukkede gjenstander, filtrert ut tomme Alternativer.

I tillegg har den flere varianter av løfte metode som løfter en Funksjon inn i en Funksjon>:

Funksjon f = (Heltall x) -> x> 0? x + 1: null; Funksjon løftet = Alternativer. heis (f); assertEquals (2, (lang) løftet. søk (Option.some (1)). get ()); assertTrue (lifted.apply (Option.none ()). isEmpty ());

Dette er nyttig når vi ønsker å passere en funksjon som ikke er klar over Alternativ til noen metode som bruker Alternativ.

Merk at, akkurat som kart metode, løfte kartlegger ikke null til Ingen:

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

4. Enten for beregninger med to mulige utfall

Som vi har sett, er Alternativ klasse tillater oss å håndtere fraværet av en verdi på en funksjonell måte.

Noen ganger trenger vi imidlertid å returnere mer informasjon enn "ingen verdi"; for eksempel vil vi kanskje returnere enten en legitim verdi eller et feilobjekt.

De Enten klasse dekker brukssaken.

En forekomst av Enten kan være en Ikke sant eller a Venstre men aldri begge samtidig.

Etter konvensjon er høyre et resultat av en vellykket beregning, mens venstre er det eksepsjonelle tilfellet.

4.1. Konstruere en Enten

Vi kan få en Enten eksempel ved å ringe en av de to statiske fabrikkmetodene.

Vi ringer Ikke sant hvis vi vil ha en Enten inneholder Ikke sant verdi:

Enten rett = Enten. Rett ("verdi");

Ellers ringer vi venstre:

Enten venstre = Enten. Venstre (-1);

Her kan beregningen vår enten returnere a String eller en Heltall.

4.2. Bruke en Enten

Når vi har en Enten For eksempel kan vi sjekke om det er venstre eller høyre og handle i samsvar med dette:

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

Mer interessant, vi kan kjede operasjoner i en funksjonell stil:

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

4.3. Anslag

Det viktigste som skiller seg fra andre monadiske verktøy som Alternativ, prøv, er det faktum at det ofte er upartisk. Enkelt sagt, hvis vi kaller map () -metoden, Enten vet ikke om jeg skal jobbe med Venstre eller Ikke sant side.

Det er her anslag kommer til nytte.

Venstre og høyre anslag er spekulære visninger av en Enten som fokuserer på venstre eller høyre verdi, henholdsvis:

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

I kodebiten ovenfor, hvis Enten er Venstre, decodeSQLErrorCode () blir brukt på det underliggende elementet. Hvis Enten er Ikke sant, det vil det ikke. Samme omvendt når du bruker riktig projeksjon.

4.4. Verktøymetoder

Som med Alternativer, Fugue tilbyr en klasse full av verktøy for Eithers, også, og det heter akkurat slik: Eithers.

Den inneholder metoder for filtrering, støping og iterering over samlinger av Entens.

5. Unntakshåndtering med Prøve

Vi avslutter vår tur til enten denne eller den datatypen i Fugue med en annen variant kalt Prøve.

Prøve den er lik Enten, men det skiller seg ut ved at det er dedikert til å arbeide med unntak.

Som Alternativ og i motsetning til Enten, Prøve er parameterisert over en enkelt type, fordi den "andre" typen er festet til Unntak (mens for Alternativ det er implisitt Tomrom).

Så, a Prøve kan være enten en Suksess eller a Feil:

assertTrue (Try.failure (new Exception ("Fail!")). isFailure ()); assertTrue (Try.successful ("OK"). isSuccess ());

5.1. Instantiering av en Prøve

Ofte lager vi ikke et Prøve eksplisitt som en suksess eller en fiasko; heller lager vi en fra en metodeanrop.

Kontrollert. Av kaller en gitt funksjon og returnerer a Prøve innkapsling av returverdien eller et kastet unntak:

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

En annen metode, Sjekket. Heis, tar en potensielt kastefunksjon og heiser den til en funksjon som returnerer a Prøve:

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

5.2. Jobber med Prøve

Når vi har en Prøve, er de tre vanligste tingene vi til slutt vil gjøre med det:

  1. utvinne verdien
  2. kjede noen operasjoner til vellykket verdi
  3. håndtering av unntaket med en funksjon

Dessuten, tydeligvis, forkastelse av Prøve eller overføring til andre metoder, er de ovennevnte tre ikke de eneste alternativene vi har, men alle de andre innebygde metodene er bare en bekvemmelighet i forhold til disse tre.

5.3. Hente ut den vellykkede verdien

For å trekke ut verdien bruker vi getOrElse metode:

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

Den returnerer den vellykkede verdien hvis den er tilstede, eller noen beregnet verdi ellers.

Det er ingen getOrTrow eller lignende, men siden getOrElse fanger ikke noe unntak, vi kan enkelt skrive det:

someTry.getOrElse (() -> {kast nytt NoSuchElementException ("Ingenting å få");});

5.4. Kjedekall etter suksess

I en funksjonell stil kan vi bruke en funksjon til suksessverdien (hvis den er tilstede) uten å trekke den eksplisitt ut først.

Dette er det typiske kart metoden vi finner i Alternativ, Enten og de fleste andre containere og samlinger:

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

Det returnerer a Prøve slik at vi kan kjede videre virksomhet.

Selvfølgelig har vi også flatMap variasjon:

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

5.5. Gjenopprette fra unntak

Vi har analoge kartoperasjoner som fungerer med unntak av a Prøve (hvis til stede), snarere enn den vellykkede verdien.

Imidlertid er disse metodene forskjellige i og med at deres betydning er å komme seg fra unntaket, dvs. å produsere en vellykket Prøve i standardtilfelle.

Dermed kan vi produsere en ny verdi med komme seg:

Prøv å gjenopprette = Prøv. Feil (nytt unntak ("boo!")). Gjenopprette ((unntak e) -> e.getMessage () + "gjenopprettet."); assertTrue (recover.isSuccess ()); assertEquals ("boo! recovered.", recover.getOrElse (() -> null));

Som vi kan se, tar gjenopprettingsfunksjonen unntaket som sitt eneste argument.

Hvis gjenopprettingsfunksjonen i seg selv kaster, er resultatet en annen mislykket Prøve:

Prøv å mislykkes = Try.failure (nytt unntak ("boo!")). Gjenopprette (x -> {kast nytt RuntimeException (x);}); assertTrue (failure.isFailure ());

Den analoge til flatMap er kalt gjenoppretteMed:

Prøv å gjenopprette = Prøv .feil (nytt unntak ("boo!")) .RecoverWith ((Unntak e) -> Try.successful ("gjenopprettet igjen!")); assertTrue (recover.isSuccess ()); assertEquals ("gjenopprettet igjen!", recover.getOrElse (() -> null));

6. Andre verktøy

La oss nå se raskt på noen av de andre verktøyene i Fugue, før vi pakker den sammen.

6.1. Par

EN Par er en veldig enkel og allsidig datastruktur, laget av to like viktige komponenter, som Fugue kaller venstre og Ikke sant:

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

Fugue gir ikke mange innebygde metoder på Pars, i tillegg til kartlegging og det applikative funktormønsteret.

Derimot, Pars brukes i hele biblioteket, og de er lett tilgjengelige for brukerprogrammer.

Den neste stakkars implementering av Lisp er bare noen få tastetrykk unna!

6.2. Enhet

Enhet er en enum med en enkelt verdi som er ment å representere "ingen verdi".

Det er en erstatning for den ugyldige returtypen og Tomrom klasse, som gjør unna null:

Enhet doSomething () {System.out.println ("Hei! Bivirkning"); retur enhet (); }

Ganske overraskende imidlertid Alternativ forstår ikke Enhet, behandler det som en verdi i stedet for ingen.

6.3. Statisk verktøy

Vi har noen få klasser fullpakket med statiske verktøymetoder som vi ikke trenger å skrive og teste.

De Funksjoner klasse tilbyr metoder som bruker og transformerer funksjoner på forskjellige måter: komposisjon, applikasjon, karri, delvis funksjoner ved bruk Alternativ, svak memoisering et cetera.

De Leverandører klasse gir en lignende, men mer begrenset samling av verktøy for Leverandørs, det vil si funksjoner uten argumenter.

Iterables og Iteratorer, til slutt, inneholder en rekke statiske metoder for å manipulere de to mye brukte standard Java-grensesnittene.

7. Konklusjon

I denne artikkelen har vi gitt en oversikt over Fugue-biblioteket av Atlassian.

Vi har ikke rørt de algebra-tunge klassene som Monoid og Halvgrupper fordi de ikke passer inn i en generalistartikkel.

Du kan imidlertid lese om dem og mer i Fugue-javadoksen og kildekoden.

Vi har heller ikke berørt noen av de valgfrie modulene, som for eksempel tilbyr integrasjoner med Guava og Scala.

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.


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