Funkčné programovanie v Jave

1. Úvod

V tomto tutoriále pochopíme základné princípy paradigmy funkčného programovania a ako ich precvičiť v programovacom jazyku Java. Ďalej sa budeme venovať niektorým pokročilým technikám funkčného programovania.

To nám tiež umožní vyhodnotiť výhody, ktoré získame z funkčného programovania, najmä v prostredí Java.

2. Čo je funkčné programovanie

V podstate funkčné programovanie je štýl písania počítačových programov, ktorý zaobchádza s výpočtami ako s hodnotením matematických funkcií. Aká je teda funkcia v matematike?

Funkcia je výraz, ktorý spája vstupnú množinu s výstupnou množinou.

Dôležité je, že výstup funkcie závisí iba od jej vstupu. Ešte zaujímavejšie je, že môžeme zostaviť dve alebo viac funkcií dohromady, aby sme získali novú funkciu.

2.1. Lambda kalkul

Aby sme pochopili, prečo sú tieto definície a vlastnosti matematických funkcií v programovaní dôležité, musíme sa vrátiť trochu späť v čase. V 30. rokoch sa rozvinul matematik Alonzo Chruch formálny systém na vyjadrenie výpočtov založených na abstrakcii funkcií. Tento univerzálny model výpočtu sa stal známym ako lambda kalkul.

Lambda kalkul mal obrovský vplyv na rozvoj teórie programovacích jazykov, najmä funkčných programovacích jazykov. Funkčné programovacie jazyky zvyčajne implementujú lambda kalkul.

Pretože lambda kalkul sa zameriava na zloženie funkcií, funkčné programovacie jazyky poskytujú expresívne spôsoby, ako zostaviť softvér v zložení funkcií.

2.2. Kategorizácia programovacích paradigiem

Funkčné programovanie samozrejme nie je v praxi jediným programovacím štýlom. Všeobecne možno programovacie štýly rozdeliť do imperatívnych a deklaratívnych paradigiem programovania:

The imperatívny prístup definuje program ako postupnosť príkazov, ktoré menia stav programu kým nedosiahne konečný stav. Procedurálne programovanie je typ imperatívneho programovania, pri ktorom konštruujeme programy pomocou procedúr alebo podprogramov. Jedna z populárnych paradigiem programovania známa ako objektovo orientované programovanie (OOP) rozširuje koncepcie procedurálneho programovania.

Naproti tomu deklaratívny prístup vyjadruje logiku výpočtu bez popisu jeho riadiaceho toku v zmysle postupnosti výrokov. Jednoducho povedané, zameraním deklaratívneho prístupu je skôr definovať, čo musí program dosiahnuť, ako to má dosiahnuť. Funkčné programovanie je podmnožinou deklaratívnych programovacích jazykov.

Tieto kategórie majú ďalšie podkategórie a taxonómia sa stáva pomerne zložitou, pre túto príručku sa však do toho nebudeme venovať.

2.3. Kategorizácia programovacích jazykov

Akýkoľvek pokus o formálnu kategorizáciu programovacích jazykov dnes je sám o sebe akademickým úsilím! Pokúsime sa však pochopiť, ako sa programovacie jazyky delia na základe ich podpory funkčného programovania pre naše účely.

Čisté funkčné jazyky, ako napríklad Haskell, umožňujú iba čisté funkčné programy.

Iné jazyky však umožňujú oboje funkčné a procedurálne programy a považujú sa za nečisté funkčné jazyky. Mnoho jazykov spadá do tejto kategórie, vrátane Scala, Kotlin a Java.

Je dôležité si uvedomiť, že väčšina populárnych programovacích jazykov súčasnosti sú univerzálne jazyky, a preto majú tendenciu podporovať viac paradigiem programovania.

3. Základné princípy a koncepcie

Táto časť sa bude zaoberať základnými princípmi funkčného programovania a ich osvojením v prostredí Java. Upozorňujeme, že veľa funkcií, ktoré budeme používať, nebolo vždy súčasťou Javy a je to tak Odporúča sa byť v prostredí Java 8 alebo novšom, aby ste mohli efektívne vykonávať funkčné programovanie.

3.1. Prvotriedne funkcie a funkcie vyššieho rádu

Hovorí sa, že programovací jazyk má prvotriedne funkcie, ak zaobchádza s funkciami ako s občanmi prvej triedy. V podstate to znamená funkcie sú povolené na podporu všetkých operácií, ktoré sú zvyčajne dostupné pre iné subjekty. Patrí sem priradenie funkcií premenným, ich odovzdanie ako argumentov iným funkciám a ich vrátenie ako hodnôt z iných funkcií.

Táto vlastnosť umožňuje definovať funkcie vyššieho rádu vo funkčnom programovaní. Funkcie vyššieho rádu sú schopné prijímať funkciu ako argumenty a vo výsledku funkciu vracať. To ďalej umožňuje niekoľko techník vo funkčnom programovaní, ako je skladanie funkcií a kari.

Tradične bolo možné odovzdávať funkcie v Jave iba pomocou konštruktov, ako sú funkčné rozhrania alebo anonymné vnútorné triedy. Funkčné rozhrania majú presne jednu abstraktnú metódu a sú známe aj ako rozhrania Single Abstract Method (SAM).

Povedzme, že musíme poskytnúť vlastný komparátor Zbierky.triediť metóda:

Collections.sort (numbers, new Comparator () {@Override public int compare (Integer n1, Integer n2) {return n1.compareTo (n2);}});

Ako vidíme, jedná sa o zdĺhavú a podrobnú techniku ​​- určite nie o niečo, čo povzbudzuje vývojárov k prijatiu funkčného programovania. Našťastie Java 8 priniesla veľa nové funkcie na uľahčenie procesu, ako sú výrazy lambda, odkazy na metódy a preddefinované funkčné rozhrania.

Pozrime sa, ako nám výraz lambda môže pomôcť s rovnakou úlohou:

Zbierky.sort (čísla, (n1, n2) -> n1.compareTo (n2));

Toto je určite výstižnejšie a zrozumiteľnejšie. Upozorňujeme však, že aj keď to v nás môže vzbudiť dojem, že v Java používame funkcie ako občania prvej triedy, nie je to tak.

Za syntaktickým cukrom výrazov lambda ich Java stále zalamuje do funkčných rozhraní. Teda Java zaobchádza s výrazom lambda ako s Objekt, čo je v skutočnosti skutočný prvotriedny občan v Jave.

3.2. Čisté funkcie

Definícia čistej funkcie to zdôrazňuje čistá funkcia by mala vrátiť hodnotu iba na základe argumentov a nemala by mať žiadne vedľajšie účinky. Teraz to môže znieť celkom v rozpore so všetkými osvedčenými postupmi v prostredí Java.

Java ako objektovo orientovaný jazyk odporúča zapuzdrenie ako základnú programátorskú prax. Podporuje skrytie vnútorného stavu objektu a odhalenie iba potrebných metód na jeho sprístupnenie a úpravu. Preto tieto metódy nie sú striktne čisté funkcie.

Zapuzdrenie a ďalšie objektovo orientované princípy sú samozrejme iba odporúčaním a nie sú v Jave záväzné. V skutočnosti si vývojári nedávno začali uvedomovať význam definovania nemenných stavov a metód bez vedľajších účinkov.

Povedzme, že chceme nájsť súčet všetkých čísel, ktoré sme práve zoradili:

Integer sum (List numbers) {return numbers.stream (). Collect (Collectors.summingInt (Integer :: intValue)); }

Teraz táto metóda závisí iba od argumentov, ktoré dostane, a preto je deterministická. Okrem toho neprodukuje žiadne vedľajšie účinky.

Vedľajšie účinky môžu byť čokoľvek okrem zamýšľaného správania metódy. Napríklad vedľajšie účinky môžu byť také jednoduché ako aktualizácia miestneho alebo globálneho stavu alebo uložením do databázy pred vrátením hodnoty. Puristi tiež považujú ťažbu dreva za vedľajší efekt, ale všetci máme svoje vlastné hranice, ktoré si musíme stanoviť!

Môžeme sa však zamyslieť nad tým, ako zaobchádzame s legitímnymi vedľajšími účinkami. Napríklad zo skutočných dôvodov možno budeme musieť výsledok uložiť do databázy. Vo funkčnom programovaní existujú techniky na zvládnutie vedľajších účinkov pri zachovaní čistých funkcií.

O niektorých si ešte povieme v ďalších častiach.

3.3. Nezmeniteľnosť

Nezmeniteľnosť je jedným zo základných princípov funkčného programovania odkazuje na vlastnosť, ktorú entita nemôže byť upravená po vytvorení inštancie. Teraz je to vo funkčnom programovacom jazyku podporované dizajnom na jazykovej úrovni. Ale v Jave musíme urobiť vlastné rozhodnutie o vytvorení nemenných dátových štruktúr.

Vezmite prosím na vedomie, že Samotná Java poskytuje niekoľko zabudovaných nemenných typov, napríklad String. Je to primárne z bezpečnostných dôvodov, pretože ich vo veľkej miere používame String pri načítaní triedy a ako kľúče v hašovacích dátových štruktúrach. Existuje niekoľko ďalších zabudovaných nemenných typov, ako sú primitívne obálky a matematické typy.

Čo však s dátovými štruktúrami, ktoré vytvárame v Jave? Samozrejme, predvolene nie sú nemenné a na dosiahnutie nemennosti musíme urobiť niekoľko zmien. The použitie konečné kľúčové slovo je jedným z nich, ale tým to nekončí:

verejná trieda ImmutableData {súkromné ​​finále String someData; súkromné ​​finále AnotherImmutableData anotherImmutableData; public ImmutableData (final String someData, final AnotherImmutableData anotherImmutableData) {this.someData = someData; this.anotherImmutableData = anotherImmutableData; } public String getSomeData () {return someData; } public AnotherImmutableData getAnotherImmutableData () {return anotherImmutableData; }} verejná trieda AnotherImmutableData {súkromné ​​konečné celé číslo someOtherData; public AnotherImmutableData (finálne celé číslo someData) {this.someOtherData = someData; } verejné celé číslo getSomeOtherData () {návrat someOtherData; }}

Upozorňujeme, že musíme dôsledne dodržiavať niekoľko pravidiel:

  • Všetky polia nemennej dátovej štruktúry musia byť nemenné
  • To platí rovnako pre všetky vnorené typy a kolekcie (vrátane toho, čo obsahujú)
  • Podľa potreby by mal byť jeden alebo viac konštruktérov na inicializáciu
  • Mali by existovať iba prístupové metódy, pravdepodobne bez vedľajších účinkov

Je to nie je ľahké zakaždým to úplne napraviť, najmä keď sa dátové štruktúry začnú komplikovať. Niekoľko externých knižníc však môže uľahčiť prácu s nemennými údajmi v Jave. Napríklad Immutables a Project Lombok poskytujú rámce pripravené na použitie na definovanie nemenných dátových štruktúr v Jave.

3.4. Referenčná transparentnosť

Referenčná transparentnosť je možno jedným z ťažšie pochopiteľných princípov funkčného programovania. Koncept je však dosť jednoduchý. My volať výraz referenčne transparentný, ak jeho nahradenie zodpovedajúcou hodnotou nemá žiadny vplyv na správanie programu.

To umožňuje niektoré výkonné techniky vo funkčnom programovaní, ako sú funkcie vyššieho rádu a lenivé hodnotenie. Aby sme tomu lepšie porozumeli, vezmime si príklad:

public class SimpleData {private Logger logger = Logger.getGlobal (); súkromné ​​údaje reťazca; public String getData () {logger.log (Level.INFO, "Získanie údajov požadovaných pre SimpleData"); návratové údaje; } verejné SimpleData setData (String data) {logger.log (Level.INFO, "Set data called for SimpleData"); this.data = údaje; vráťte to; }}

Toto je typická trieda POJO v Jave, ale zaujíma nás, či poskytuje referenčnú transparentnosť. Dodržiavajme nasledujúce tvrdenia:

Reťazec data = new SimpleData (). SetData ("Baeldung"). GetData (); logger.log (Level.INFO, new SimpleData (). setData ("Baeldung"). getData ()); logger.log (Level.INFO, data); logger.log (Level.INFO, "Baeldung");

Tri volania na číslo drevorubač sú sémanticky rovnocenné, ale nie referenčne transparentné. Prvé volanie nie je referenčne transparentné, pretože vyvoláva vedľajší efekt. Ak nahradíme tento hovor jeho hodnotou ako v treťom hovore, protokoly nám budú chýbať.

Druhá výzva tiež nie je referenčne transparentná SimpleData je premenlivý. Výzva na data.setData kdekoľvek v programe by to sťažilo jeho nahradenie jeho hodnotou.

Takže v podstate kvôli referenčnej transparentnosti potrebujeme, aby naše funkcie boli čisté a nemenné. Toto sú dva predpoklady, o ktorých sme už hovorili skôr. Ako zaujímavý výsledok referenčnej transparentnosti vyrábame bezkontextový kód. Inými slovami, môžeme ich vykonať v akomkoľvek poradí a kontexte, čo vedie k rôznym možnostiam optimalizácie.

4. Techniky funkčného programovania

Princípy funkčného programovania, o ktorých sme hovorili vyššie, nám umožňujú využívať niekoľko techník na to, aby sme mohli ťažiť z funkčného programovania. V tejto časti sa budeme venovať niektorým z týchto populárnych techník a pochopíme, ako ich môžeme implementovať v prostredí Java.

4.1. Zloženie funkcie

Skladba funkcií označuje skladanie zložitých funkcií kombináciou jednoduchších funkcií. To sa primárne dosahuje v Jave pomocou funkčných rozhraní, ktoré sú v skutočnosti cieľovými typmi pre výrazy lambda a odkazy na metódy.

Typicky akékoľvek rozhranie s jednou abstraktnou metódou môže slúžiť ako funkčné rozhranie. Preto môžeme pomerne ľahko definovať funkčné rozhranie. Java 8 nám však štandardne poskytuje veľa funkčných rozhraní pre rôzne prípady použitia v rámci balíka java.util.funkcia.

Mnoho z týchto funkčných rozhraní poskytuje podporu pre zloženie funkcií v zmysle predvolené a statický metódy. Vyberieme Funkcia aby ste tomu lepšie porozumeli. Funkcia je jednoduché a všeobecné funkčné rozhranie, ktoré prijíma jeden argument a vytvára výsledok.

Poskytuje tiež dve predvolené metódy, komponovať a a potom, ktoré nám pomôžu pri skladbe funkcií:

Protokol funkcie = (hodnota) -> Math.log (hodnota); Funkcia sqrt = (hodnota) -> Math.sqrt (hodnota); Funkcia logThenSqrt = sqrt.compose (log); logger.log (Level.INFO, String.valueOf (logThenSqrt.apply (3.14)))); // Výstup: 1,06 Funkcia sqrtThenLog = sqrt.andThen (log); logger.log (Level.INFO, String.valueOf (sqrtThenLog.apply (3.14))); // Výstup: 0,57

Obe tieto metódy nám umožňujú zostaviť viac funkcií do jednej funkcie, ale ponúkajú inú sémantiku. Zatiaľ čo komponovať najskôr použije funkciu odovzdanú v argumente a potom funkciu, na ktorú je vyvolaná, a potom to isté robí opačne.

Niekoľko ďalších funkčných rozhraní má zaujímavé metódy na použitie vo funkčnej kompozícii, napríklad predvolené metódy a aleboa negovať v Predikát rozhranie. Aj keď tieto funkčné rozhrania prijímajú jediný argument, existujú dvojšpecializované špecializácie, napríklad BiFunkcia a BiPredicate.

4.2. Monády

Mnoho konceptov funkčného programovania pochádza z teórie kategórie, čo je všeobecná teória funkcií v matematike. Predstavuje niekoľko konceptov kategórií, ako sú funktory a prirodzené transformácie. Pre nás je len dôležité vedieť, že toto je základ použitia monád vo funkčnom programovaní.

Formálne je monáda abstrakciou, ktorá umožňuje všeobecnú štruktúru programov. Takže v podstate monáda umožňuje nám zabaliť hodnotu, použiť množinu transformácií a získať hodnotu späť so všetkými použitými transformáciami. Samozrejme, existujú tri zákony, ktoré musí každý monád dodržiavať - ​​ľavá identita, pravá identita a asociatívnosť - ale nebudeme sa rozpisovať.

V Jave existuje niekoľko monád, ktoré používame pomerne často Voliteľné a Prúd:

Optional.of (2) .flatMap (f -> Optional.of (3) .flatMap (s -> Optional.of (f + s)))

Prečo teda voláme Voliteľné monáda? Tu, Voliteľné nám umožňuje zabaliť hodnotu pomocou metódy z a použiť sériu transformácií. Aplikujeme transformáciu pridania ďalšej zabalenej hodnoty pomocou metódy flatMap.

Ak chceme, môžeme to ukázať Voliteľné riadi sa tromi zákonmi monád. Kritici však budú rýchlo poukazovať na to, že Voliteľné za určitých okolností porušuje monadské zákony. Ale pre väčšinu praktických situácií by to malo byť pre nás dosť dobré.

Ak pochopíme základy monád, čoskoro si uvedomíme, že v Jave existuje veľa ďalších príkladov Prúd a CompletableFuture. Pomáhajú nám dosiahnuť rôzne ciele, ale všetky majú štandardné zloženie, v ktorom sa manipuluje s kontextovou manipuláciou alebo transformáciou.

Samozrejme, môžeme definovať naše vlastné typy monád v Jave na dosiahnutie rôznych cieľov ako log monad, report monad alebo audit monad. Pamätáte si, ako sme diskutovali o riešení vedľajších účinkov vo funkčnom programovaní? Ako sa zdá, monad je jednou z techník funkčného programovania, ktorá to umožňuje.

4.3. Kari

Currying je matematické technika prevodu funkcie, ktorá berie viac argumentov, na postupnosť funkcií, ktoré prijímajú jeden argument. Prečo ich však potrebujeme vo funkčnom programovaní? Poskytuje nám výkonnú kompozičnú techniku, pri ktorej nepotrebujeme volať funkciu so všetkými jej argumentmi.

Navyše, funkcia curried si neuvedomuje svoj účinok, kým nedostane všetky argumenty.

V čisto funkčných programovacích jazykoch, ako je Haskell, je kari dobre podporované. Všetky funkcie sú v skutočnosti predvolené. Avšak v Jave to nie je také priame:

Funkcia hmotnosť = hmotnosť -> gravitácia -> hmotnosť * gravitácia; Funkcia weightOnEarth = weight.apply (9,81); logger.log (Level.INFO, „Moja váha na Zemi:“ + weightOnEarth.apply (60,0)); Funkcia weightOnMars = weight.apply (3,75); logger.log (Level.INFO, „Moja váha na Marse:“ + weightOnMars.apply (60,0));

Tu sme definovali funkciu na výpočet našej hmotnosti na planéte. Aj keď naša hmotnosť zostáva rovnaká, gravitácia sa líši podľa planéty, na ktorej sme. My môže čiastočne použiť funkciu prejdením iba gravitácie, aby sme definovali funkciu pre konkrétnu planétu. Túto čiastočne aplikovanú funkciu môžeme navyše odovzdať ako argument alebo návratovú hodnotu pre ľubovoľné zloženie.

Kari závisí od jazyka, ktorý poskytuje dve základné funkcie: výrazy lambda a uzávierky. Výrazy lambda sú anonymné funkcie, ktoré nám pomáhajú považovať kód za údaj. Už skôr sme videli, ako ich implementovať pomocou funkčných rozhraní.

Teraz sa výraz lambda môže uzavrieť na svoj lexikálny rozsah, ktorý definujeme ako jeho uzavretie. Pozrime sa na príklad:

súkromná statická funkcia weightOnEarth () {konečná dvojitá gravitácia = 9,81; spätná hmotnosť -> hmotnosť * gravitácia; }

Vezmite prosím na vedomie, ako výraz lambda, ktorý vrátime vyššie uvedenou metódou, závisí od priloženej premennej, ktorú nazývame záver. Na rozdiel od iných funkčných programovacích jazykov Java má obmedzenie, že ohraničujúci rozsah musí byť konečný alebo skutočne konečný.

Ako zaujímavý výsledok, currying nám tiež umožňuje vytvoriť funkčné rozhranie v Jave s ľubovoľnou aritou.

4.4. Rekurzia

Rekurzia je ďalšia výkonná technika vo funkčnom programovaní umožňuje nám rozdeliť problém na menšie kúsky. Hlavnou výhodou rekurzie je, že nám pomáha eliminovať vedľajšie účinky, čo je typické pre akékoľvek imperatívne vytváranie štýlov.

Pozrime sa, ako vypočítame faktoriál čísla pomocou rekurzie:

Celočíselný faktoriál (celé číslo) {návrat (číslo == 1)? 1: číslo * faktoriál (číslo - 1); }

Tu voláme tú istú funkciu rekurzívne, kým nedosiahneme základný prípad a potom začneme počítať náš výsledok.Všimnite si, že uskutočňujeme rekurzívne volanie pred výpočtom výsledku v každom kroku alebo slovami v záhlaví výpočtu. Teda tento štýl rekurzie je tiež známy ako rekurzia hlavy.

Nevýhodou tohto typu rekurzie je, že každý krok musí udržiavať stav všetkých predchádzajúcich krokov, kým nedosiahneme základný prípad. Pre malý počet to skutočne nie je problém, ale udržať štát pre veľký počet môže byť neefektívne.

Riešením je a mierne odlišná implementácia rekurzie známej ako chvostová rekurzia. Tu zaistíme, aby rekurzívne volanie bolo posledným volaním funkcie. Pozrime sa, ako môžeme prepísať vyššie uvedenú funkciu na použitie chvostovej rekurzie:

Celočíselný faktoriál (celé číslo, výsledok celého čísla) {návrat (číslo == 1)? výsledok: faktoriál (číslo - 1, výsledok * číslo); }

Všimnite si, že vo funkcii je použitý akumulátor, ktorý eliminuje potrebu udržiavať stav na každom kroku rekurzie. Skutočnou výhodou tohto štýlu je využitie optimalizácie kompilátora, kde sa kompilátor môže rozhodnúť uvoľniť rámec zásobníka aktuálnej funkcie, čo je technika známa ako eliminácia spätného volania.

Zatiaľ čo mnoho jazykov, ako je Scala, podporuje elimináciu koncových hovorov, Java to stále nepodporuje. Toto je súčasť nevybavených súborov Java a možno sa do určitej podoby dostane ako súčasť väčších zmien navrhovaných v rámci projektu Loom.

5. Prečo je dôležité funkčné programovanie?

Po absolvovaní doterajšieho tutoriálu si musíme položiť otázku, prečo vôbec chceme vynaložiť toľko úsilia. Pre niekoho, kto pochádza z prostredia Java, posun, ktorý požiadavky na funkčné programovanie nie sú malicherné. Prijatie funkčného programovania v Jave by teda malo mať skutočne sľubné výhody.

Najväčšou výhodou prijatia funkčného programovania v akomkoľvek jazyku vrátane jazyka Java je čisté funkcie a nemenné stavy. Ak uvažujeme spätne, väčšina programovacích výziev má ten či onak korene v nežiaducich účinkoch a premenlivom stave. Jednoducho sa ich zbaviť uľahčuje čítanie, uvažovanie, testovanie a údržbu nášho programu.

Deklaratívne programovanie ako také, vedie k veľmi stručným a čitateľným programom. Funkčné programovanie, ktoré je podmnožinou deklaratívneho programovania, ponúka niekoľko konštrukcií, ako sú funkcie vyššieho rádu, zloženie funkcií a reťazenie funkcií. Pomysli na výhody, ktoré Stream API prinieslo do Javy 8 pre manipuláciu s dátami.

Nenechajte sa však zlákať na prepnutie, pokiaľ nebudete úplne pripravení. Upozorňujeme, že funkčné programovanie nie je jednoduchý návrhový vzor, ​​ktorý môžeme okamžite použiť a ťažiť z neho. Funkčné programovanie je skôr zmenu v tom, ako uvažujeme o problémoch a ich riešeniach a ako štruktúrovať algoritmus.

Než teda začneme používať funkčné programovanie, musíme sa trénovať, aby sme o svojich programoch premýšľali z hľadiska funkcií.

6. Je Java vhodná?

Aj keď je ťažké poprieť výhody funkčného programovania, nemôžeme si pomôcť a pýtať sa sami seba, či je Java preň vhodnou voľbou. Historicky, Java sa vyvinula ako univerzálny programovací jazyk vhodnejší pre objektovo orientované programovanie. Už aj pomyslenie na použitie funkčného programovania pred Java 8 bolo zdĺhavé! Ale po Java 8 sa veci definitívne zmenili.

Samotný fakt, že v Jave neexistujú žiadne skutočné typy funkcií ide proti základným princípom funkčného programovania. Funkčné rozhrania v maskovaní výrazov lambda to do veľkej miery kompenzujú, prinajmenšom syntakticky. Potom skutočnosť, že typy v Jave sú inherentne premenlivé a musíme napísať toľko variácií, aby sme vytvorili nemenné typy, to nepomáha.

Očakávame ďalšie veci od funkčného programovacieho jazyka, ktoré v Jave chýbajú alebo sú náročné. Napríklad predvolená stratégia hodnotenia argumentov v Jave je dychtivá. Lenivé hodnotenie je však efektívnejším a odporúčanejším spôsobom vo funkčnom programovaní.

Stále môžeme dosiahnuť lenivé hodnotenie v Jave pomocou skratu operátora a funkčných rozhraní, ale je to viac zapojené.

Zoznam určite nie je úplný a môže obsahovať podporu generík s mazaním typov, chýbajúcu podporu pre optimalizáciu koncových hovorov a ďalšie veci. Získame však širokú predstavu. Java rozhodne nie je vhodná na spustenie programu od nuly vo funkčnom programovaní.

Čo však v prípade, že už máme existujúci program napísaný v Jave, pravdepodobne v objektovo orientovanom programovaní? Nič nám nebráni v získaní niektorých výhod funkčného programovania, najmä v prostredí Java 8.

To je miesto, kde väčšina výhod funkčného programovania spočíva v vývojárovi Java. Kombinácia objektovo orientovaného programovania s výhodami funkčného programovania môže prejsť dlhú cestu.

7. Záver

V tomto návode sme si prešli základy funkčného programovania. Prebrali sme základné princípy a to, ako ich môžeme prijať v Jave. Ďalej sme diskutovali o niektorých populárnych technikách vo funkčnom programovaní pomocou príkladov v Jave.

Nakoniec sme sa venovali niektorým výhodám prijatia funkčného programovania a odpovedali sme, či je Java vhodná pre to isté.

Zdrojový kód článku je k dispozícii na GitHub.