Bevezetés a funkcionális Java-ba

1. Áttekintés

Ebben az oktatóanyagban rövid áttekintést nyújtunk a funkcionális Java könyvtárról, néhány példával együtt.

2. A funkcionális Java könyvtár

A Funkcionális Java könyvtár egy nyílt forráskódú könyvtár, amely a Java funkcionális programozását hivatott megkönnyíteni. A könyvtár rengeteg alapvető és haladó programozási absztrakciót tartalmaz, amelyeket a funkcionális programozásban általában használnak.

A könyvtár funkcionalitásának nagy része a F felület. Ez F Az interfész olyan funkciót modellez, amely típusú bemenetet vesz fel A és egy típusú kimenetet ad vissza B. Mindez a Java saját típusú rendszerére épül.

3. Maven-függőségek

Először hozzá kell adnunk a szükséges függőségeket a sajátunkhoz pom.xml fájl:

 org.functionaljavactionaljava 4.8.1 org.functionaljava funkcionálisjava-java8 4.8.1 org.functionaljava funkcionálisjava-quickcheck 4.8.1 org.functionaljava funkcionálisvajava-java-core 4.8.1 

4. Funkció meghatározása

Kezdjük egy olyan függvény létrehozásával, amelyet később a példáinkban használhatunk.

Funkcionális Java nélkül az alapvető szorzási módszer a következőképpen néz ki:

public static final Integer timesTwoRegular (Integer i) {return i * 2; }

A Functional Java könyvtár használatával egy kicsit elegánsabban definiálhatjuk ezt a funkciót:

nyilvános statikus végső F időkKét = i -> i * 2;

Fentebb a F interfész, amely egy Egész szám bemenetként és ezt adja vissza Egész szám kétszer a kimenete.

Itt van egy másik példa egy alapfunkcióra, amely egy Egész szám bemenetként, de ebben az esetben a Logikai annak jelzésére, hogy a bemenet páros vagy páratlan volt-e:

nyilvános statikus végső F isEven = i -> i% 2 == 0;

5. Funkció alkalmazása

Most, hogy a helyünkön vannak a funkcióink, alkalmazzuk őket egy adatkészletre.

A funkcionális Java könyvtár az adatok, például listák, halmazok, tömbök és térképek kezeléséhez a szokásos típusú készletet biztosítja. A legfontosabb tudomásul venni, hogy ezek az adattípusok megváltoztathatatlanok.

Ezenkívül a könyvtár biztosítja kényelmi funkciók a standard Java Gyűjtemények osztályokba történő átváltására ha szükséges.

Az alábbi példában meghatározzuk az egész számok listáját és alkalmazzuk a timesTwo funkciót. Mi is felhívjuk térkép ugyanazon függvény belső definíciójának felhasználásával. Természetesen elvárjuk, hogy az eredmények azonosak legyenek:

public void multiplyNumbers_givenIntList_returnTrue () {List fList = List.list (1, 2, 3, 4); FList1 = fList.map (timesTwo) lista; FList2 = fList.map (i -> i * 2) lista; assertTrue (fList1.egyenlő (fList2)); }

Ahogy látjuk térkép egy azonos méretű listát ad vissza, ahol minden elem értéke az alkalmazott függvény mellett a bemeneti lista értéke. Maga az input lista nem változik.

Itt van egy hasonló példa a mi használatunkkal egyenlő funkció:

public void calcEvenNumbers_givenIntList_returnTrue () {List fList = List.list (3, 4, 5, 6); List evenList = fList.map (isEven); List evenListTrueResult = List.list (hamis, igaz, hamis, igaz); assertTrue (evenList.equals (evenListTrueResult)); }

Mivel a térkép A method egy listát ad vissza, a kimenetére egy másik függvényt is alkalmazhatunk. A sorrend, amelyben a mi magunkra hivatkozunk térkép függvények megváltoztatják az eredményt:

public void ApplyMultipleFunctions_givenIntList_returnFalse () {List fList = List.list (1, 2, 3, 4); FList1 = fList.map (timesTwo) .map (plusOne) lista; FList2 = fList.map (plusOne) .map (timesTwo) lista; assertFalse (fList1.egyenlő (fList2)); }

A fenti listák kimenete a következő lesz:

Lista (3,5,7,9) Lista (4,6,8,10)

6. Szűrés egy funkció használatával

A Funkcionális programozás másik gyakran használt művelete a vegyen be egy adatbevitelt és szűrje ki az adatokat néhány szempont alapján. És amint valószínűleg már sejtette, ezeket a szűrési feltételeket egy függvény formájában biztosítják. Ennek a funkciónak vissza kell adnia egy logikai értéket annak jelzésére, hogy az adatokat be kell-e foglalni a kimenetbe.

Most használjuk a mi egyenlő funkció a páratlan számok kiszűrésére egy bemeneti tömbből a szűrő módszer:

public void filterList_givenIntList_returnResult () {Array array = Array.array (3, 4, 5, 6); Tömb filteredArray = tömb.szűrő (isEven); Tömb eredménye = tömb.tégla (4, 6); assertTrue (filteredArray.equals (eredmény)); }

Egy érdekes megfigyelés, hogy ebben a példában egy Sor a helyett Lista amint azt az előző példákban használtuk, és a funkciónk jól működött. A függvények kivonatolásának és végrehajtásának módja miatt nem kell tisztában lenniük azzal, hogy a bemenet és a kimenet milyen módszerrel kerültek felhasználásra.

Ebben a példában a sajátunkat is használtuk egyenlő funkció, de a funkcionális Java sajátja Egész szám osztály rendelkezik az alapvető numerikus összehasonlításokra vonatkozó standard funkciókkal is.

7. Logikai logika alkalmazása egy függvény használatával

A funkcionális programozásban gyakran használunk olyan logikát, mint „csak akkor tesszük ezt, ha minden elem megfelel valamilyen feltételnek”, vagy „csak akkor tesszük ezt, ha legalább egy elem kielégít valamilyen feltételt”.

A funkcionális Java könyvtár gyorsbillentyűket biztosít ehhez a logikához a létezik és a mindenkinek mód:

public void checkForLowerCase_givenStringArray_returnResult () {Array array = Array.array ("Welcome", "To", "baeldung"); assertTrue (tömb. létezik (s -> List.fromString (s) .forall (Karakterek.isLowerCase))); Array array2 = Array.array ("Welcome", "To", "Baeldung"); assertFalse (array2.exist (s -> List.fromString (s) .forall (Characters.isLowerCase))); assertFalse (tömb.forall (s -> List.fromString (s) .forall (Karakterek.isLowerCase))); }

A fenti példában stringek tömbjét használtuk bemenetként. Felhívás a fromString függvény a tömb mindegyik karakterláncát karakterlistává alakítja. Az említett listák mindegyikére alkalmaztuk összes (Characters.isLowerCase).

Ahogy valószínűleg sejtette, Karakterek.isLowerCase olyan függvény, amely igazat ad vissza, ha egy karakter kisbetűs. Tehát alkalmazni összes (Characters.isLowerCase) karakterlista csak visszatér igaz ha a teljes lista kisbetűkből áll, ami viszont azt jelzi, hogy az eredeti karakterlánc mind kisbetűs volt.

Az első két tesztben használtuk létezik mert csak azt akartuk tudni, hogy legalább egy húr kisbetűs-e. A harmadik alkalmazott teszt mindenkinek hogy ellenőrizze, hogy az összes karakter kisbetűs-e.

8. Az opcionális értékek kezelése egy funkcióval

Az opcionális értékek kódban történő kezelése általában megköveteli == null vagy isNotBlank ellenőrzések. A Java 8 most biztosítja a Választható osztály, hogy elegánsabban kezelje ezeket az ellenőrzéseket, a Functional Java könyvtár pedig egy hasonló konstrukciót kínál a hiányzó adatok finom kezelésére az Option osztályon keresztül:

public void checkOptions_givenOptions_returnResult () {n1 opció = Option.some (1); N2 opció = Option.some (2); N3 opció = Option.none (); F function = i -> i% 2 == 0? Option.some (i + 100): Option.none (); Opció eredménye1 = n1.köt (függvény); Opció eredménye2 = n2.köt (függvény); Opció eredménye3 = n3.köt (függvény); assertEquals (Option.none (), eredmény1); assertEquals (Option.some (102), eredmény2); assertEquals (Option.none (), eredmény3); }

9. Egy készlet csökkentése egy funkció használatával

Végül megvizsgáljuk a funkcionalitást a készlet csökkentése érdekében. A „készlet csökkentése” divatos módja annak, hogy „összegyűjtsük egy értékre”.

A funkcionális Java könyvtár ezt a funkcionalitást hajtogatásnak nevezi.

Meg kell adni egy függvényt annak jelzésére, hogy mit jelent az elem hajtogatása. Erre példa a Egész számok A tömbben vagy listában szereplő egész számok megjelenítéséhez hozzá kell adni a függvényt.

Annak alapján, hogy a funkció milyen hajtogatást hajt végre, az eredmény attól függően változhat, hogy jobbról vagy balról kezdi-e a hajtogatást. Ezért a funkcionális Java könyvtár mindkét verziót biztosítja:

public void foldLeft_givenArray_returnResult () {Array intArray = Array.array (17, 44, 67, 2, 22, 80, 1, 27); int sumAll = intArray.foldLeft (Egészek.add, 0); assertEquals (260, sumAll); int sumEven = intArray.filter (isEven) .foldLeft (Integers.add, 0); assertEquals (148, sumEven); }

Az első foldBal egyszerűen összeadja az összes számot. Míg a második először szűrőt alkalmaz, majd hozzáadja a fennmaradó egész számokat.

10. Következtetés

Ez a cikk csak egy rövid bevezetés a Functional Java könyvtárba.

Mint mindig, a cikk teljes forráskódja elérhető a GitHubon.