Funkcionalno programiranje u Javi

1. Uvod

U ovom uputstvu razumjet ćemo temeljna načela paradigme funkcionalnog programiranja i kako ih primjenjivati ​​u programskom jeziku Java. Također ćemo pokriti neke od naprednih tehnika funkcionalnog programiranja.

To će nam također omogućiti da procijenimo koristi koje imamo od funkcionalnog programiranja, posebno u Javi.

2. Što je funkcionalno programiranje

U osnovi, funkcionalno programiranje jest stil pisanja računalnih programa koji računanje tretiraju kao vrednovanje matematičkih funkcija. Dakle, što je funkcija u matematici?

Funkcija je izraz koji povezuje ulazni skup s izlaznim skupom.

Važno je da izlaz funkcije ovisi samo o njezinu ulazu. Još zanimljivije, možemo zajedno sastaviti dvije ili više funkcija da bismo dobili novu funkciju.

2.1. Lambda račun

Da bismo razumjeli zašto su ove definicije i svojstva matematičkih funkcija važne u programiranju, morat ćemo se vratiti u prošlost. Tridesetih godina prošlog stoljeća razvija se matematičar Alonzo Chruch formalni sustav za izražavanje izračuna na temelju apstrakcije funkcije. Ovaj univerzalni model računanja postao je poznat kao Lambda račun.

Lambda račun imao je ogroman utjecaj na razvoj teorije programskih jezika, posebno funkcionalnih programskih jezika. Tipično, funkcionalni programski jezici implementiraju lambda račun.

Kako se lambda-račun fokusira na sastav funkcije, funkcionalni programski jezici pružaju izražajne načine za sastavljanje softvera u sastavu funkcije.

2.2. Kategorizacija programskih paradigmi

Naravno, funkcionalno programiranje nije jedini stil programiranja u praksi. Široko govoreći, stilovi programiranja mogu se svrstati u imperativne i deklarativne programske paradigme:

The imperativni pristup definira program kao slijed izjava koje mijenjaju stanje programa dok ne dosegne konačno stanje. Proceduralno programiranje vrsta je imperativnog programiranja gdje programe izrađujemo koristeći postupke ili potprograme. Jedna od popularnih paradigmi programiranja poznata kao objektno orijentirano programiranje (OOP) proširuje koncepte proceduralnog programiranja.

Suprotno tome, deklarativni pristup izražava logiku izračuna bez opisivanja njegovog toka upravljanja u smislu niza iskaza. Jednostavno rečeno, fokus deklarativnog pristupa je definirati što program mora postići, a ne kako bi to trebao postići. Funkcionalno programiranje podskup je deklarativnih programskih jezika.

Te kategorije imaju daljnje potkategorije, a taksonomija postaje prilično složena, ali u to se nećemo upuštati u ovaj vodič.

2.3. Kategorizacija programskih jezika

Svaki pokušaj formalne kategorizacije programskih jezika danas je akademski napor sam po sebi! Međutim, pokušat ćemo razumjeti kako se programski jezici dijele na temelju njihove podrške funkcionalnom programiranju u naše svrhe.

Čisti funkcionalni jezici, poput Haskella, dopuštaju samo čiste funkcionalne programe.

Međutim, drugi jezici dopuštaju oboje funkcionalni i proceduralni programi i smatraju se nečistim funkcionalnim jezicima. Mnogi jezici spadaju u ovu kategoriju, uključujući Scala, Kotlin i Java.

Važno je razumjeti da su većina popularnih programskih jezika danas jezici opće namjene, pa stoga imaju tendenciju podržavati više programskih paradigmi.

3. Temeljni principi i koncepti

Ovaj će odjeljak pokriti neka od osnovnih načela funkcionalnog programiranja i kako ih usvojiti u Javi. Imajte na umu da mnoge značajke koje ćemo koristiti nisu uvijek bile dio Jave i to jest preporučljivo je biti na Javi 8 ili novijoj verziji za učinkovito vježbanje funkcionalnog programiranja.

3.1. Prvorazredne i funkcije višeg reda

Za programski jezik se kaže da ima prvoklasne funkcije ako se prema njima ponaša kao prema prvorazrednim građanima. U osnovi, to znači funkcije mogu podržavati sve operacije koje su obično dostupne drugim entitetima. To uključuje dodjeljivanje funkcija varijablama, njihovo prosljeđivanje kao argumente drugim funkcijama i vraćanje kao vrijednosti iz drugih funkcija.

Ovo svojstvo omogućuje definiranje funkcija višeg reda u funkcionalnom programiranju. Funkcije višeg reda sposobne su primati funkciju kao argumente i vraćati funkciju kao rezultat. To nadalje omogućuje nekoliko tehnika u funkcionalnom programiranju poput sastavljanja funkcija i kariranja.

Tradicionalno je bilo moguće prenositi funkcije u Javi koristeći konstrukcije poput funkcionalnih sučelja ili anonimnih unutarnjih klasa. Funkcionalna sučelja imaju točno jednu apstraktnu metodu, a poznata su i kao sučelja s jednom apstraktnom metodom (SAM).

Recimo da moramo pružiti prilagođenu usporedbu za Zbirke.sort metoda:

Collections.sort (brojevi, novi komparator () {@Preuzmi javnu int usporedbu (cijeli broj n1, cijeli broj n2) {return n1.compareTo (n2);}});

Kao što vidimo, ovo je zamorna i opširna tehnika - sigurno ne nešto što potiče programere da usvoje funkcionalno programiranje. Srećom, Java 8 donijela je mnoge nove značajke za olakšavanje postupka, poput lambda izraza, referenci metoda i unaprijed definiranih funkcionalnih sučelja.

Pogledajmo kako nam lambda izraz može pomoći u istom zadatku:

Collections.sort (brojevi, (n1, n2) -> n1.compareTo (n2));

Definitivno, ovo je sažetije i razumljivije. Međutim, imajte na umu da iako ovo može stvoriti dojam da koristimo funkcije kao prvorazredni građani na Javi, to nije slučaj.

Iza sintaktičkog šećera lambda izraza, Java ih još uvijek umotava u funkcionalna sučelja. Stoga, Java tretira lambda izraz kao Objekt, koji je u stvari pravi prvoklasni građanin Jave.

3.2. Čiste funkcije

Definicija čiste funkcije to naglašava čista funkcija treba vratiti vrijednost koja se temelji samo na argumentima i ne bi trebala imati nuspojave. Sada ovo može zvučati sasvim suprotno svim najboljim praksama u Javi.

Java, kao objektno orijentirani jezik, preporučuje enkapsulaciju kao osnovnu praksu programiranja. Potiče skrivanje unutarnjeg stanja objekta i izlaganje samo potrebnih metoda za pristup i izmjenu. Stoga ove metode nisu strogo čiste funkcije.

Naravno, enkapsulacija i drugi objektno orijentirani principi samo su preporuke i nisu obvezujući u Javi. U stvari, programeri su nedavno počeli shvaćati vrijednost definiranja nepromjenjivih stanja i metoda bez nuspojava.

Recimo da želimo pronaći zbroj svih brojeva koje smo upravo razvrstali:

Integer zbroj (Brojevi popisa) {return numbers.stream (). Collect (Collectors.summingInt (Integer :: intValue)); }

Ova metoda ovisi samo o argumentima koje prima, stoga je deterministička. Štoviše, ne proizvodi nikakve nuspojave.

Nuspojave mogu biti sve osim predviđenog ponašanja metode. Na primjer, nuspojave mogu biti jednostavne poput ažuriranja lokalne ili globalne države ili spremanje u bazu podataka prije vraćanja vrijednosti. Puristi također drvljenje bilježe kao nuspojavu, ali svi mi moramo postaviti svoje granice!

Međutim, možemo razmišljati o tome kako se bavimo legitimnim nuspojavama. Na primjer, možda ćemo trebati spremiti rezultat u bazu podataka iz istinskih razloga. Pa, postoje tehnike u funkcionalnom programiranju za rješavanje nuspojava uz zadržavanje čistih funkcija.

O nekima ćemo razgovarati u kasnijim odjeljcima.

3.3. Nepromjenljivost

Nepromjenjivost je jedno od temeljnih načela funkcionalnog programiranja i to odnosi se na svojstvo da se entitet ne može mijenjati nakon instanciranja. Sada u funkcionalnom programskom jeziku to podržava dizajn na razini jezika. Ali u Javi moramo donijeti vlastitu odluku o stvaranju nepromjenjivih struktura podataka.

Imajte na umu da Sama Java nudi nekoliko ugrađenih nepromjenjivih tipova, na primjer, Niz. To je prije svega iz sigurnosnih razloga, kako mi to jako koristimo Niz u učitavanju klase i kao ključevi u strukturama podataka temeljenim na raspršivanju. Postoji nekoliko drugih ugrađenih nepromjenjivih tipova poput primitivnih omotača i matematičkih vrsta.

Ali što je sa strukturama podataka koje stvaramo u Javi? Naravno, oni nisu nepromjenjivi prema zadanim postavkama, a mi moramo napraviti nekoliko promjena da bismo postigli nepromjenjivost. The korištenje konačni ključna riječ je jedan od njih, ali tu se ne zaustavlja:

javna klasa ImmutableData {private final String someData; privatni konačni AnotherImmutableData anotherImmutableData; public ImmutableData (final String someData, final AnotherImmutableData anotherImmutableData) {this.someData = someData; this.anotherImmutableData = anotherImmutableData; } javni String getSomeData () {return someData; } public AnotherImmutableData getAnotherImmutableData () {return anotherImmutableData; }} javna klasa AnotherImmutableData {private final Integer someOtherData; public AnotherImmutableData (final Integer someData) {this.someOtherData = someData; } javni Integer getSomeOtherData () {return someOtherData; }}

Napominjemo da moramo marljivo poštivati ​​nekoliko pravila:

  • Sva polja nepromjenjive strukture podataka moraju biti nepromjenjiva
  • To se mora odnositi i na sve ugniježđene tipove i zbirke (uključujući ono što sadrže)
  • Prema potrebi trebao bi postojati jedan ili više konstruktora za inicijalizaciju
  • Trebale bi postojati samo metode pristupa, vjerojatno bez nuspojava

To je nije lako svaki put to potpuno ispraviti, posebno kada se strukture podataka počnu složiti. Međutim, nekoliko vanjskih knjižnica može olakšati rad s nepromjenjivim podacima u Javi. Na primjer, Immutables i Project Lombok pružaju spremne okvire za definiranje nepromjenjivih struktura podataka u Javi.

3.4. Referentna transparentnost

Referentna transparentnost možda je jedno od teže razumljivih načela funkcionalnog programiranja. Koncept je ipak prilično jednostavan. Mi poziv izrazom referencijalno prozirnim ako njegova zamjena odgovarajućom vrijednošću nema utjecaja na ponašanje programa.

To omogućuje neke moćne tehnike u funkcionalnom programiranju poput funkcija višeg reda i lijene procjene. Da bismo ovo bolje razumjeli, uzmimo primjer:

javna klasa SimpleData {private Logger logger = Logger.getGlobal (); privatni niz podataka; javni String getData () {logger.log (Level.INFO, "Dohvati podatke za SimpleData"); vratiti podatke; } javni SimpleData setData (podaci niza) {logger.log (Level.INFO, "Postavi podatke pozvane za SimpleData"); this.data = podaci; vrati ovo; }}

Ovo je tipična POJO klasa na Javi, ali nas zanima je li to pruža referencijalnu transparentnost. Promotrimo sljedeće izjave:

Podaci niza = novi SimpleData (). SetData ("Baeldung"). GetData (); logger.log (Level.INFO, novi SimpleData (). setData ("Baeldung"). getData ()); logger.log (Level.INFO, podaci); logger.log (Level.INFO, "Baeldung");

Tri poziva na drvosječa semantički su ekvivalentni, ali nisu referentno transparentni. Prvi poziv nije referentno transparentan jer proizvodi nuspojavu. Ako ovaj poziv zamijenimo njegovom vrijednošću kao u trećem pozivu, propustit ćemo zapisnike.

Drugi poziv također nije referentno transparentan kao SimpleData je promjenjiv. Poziv na data.setData bilo gdje u programu otežat će zamjenu svojom vrijednošću.

U osnovi, za referentnu transparentnost trebamo da naše funkcije budu čiste i nepromjenjive. To su dva preduvjeta o kojima smo već razgovarali. Kao zanimljiv ishod referentne transparentnosti proizvodimo kod bez konteksta. Drugim riječima, možemo ih izvršiti u bilo kojem redoslijedu i kontekstu, što dovodi do različitih mogućnosti optimizacije.

4. Tehnike funkcionalnog programiranja

Principi funkcionalnog programiranja o kojima smo ranije razgovarali omogućuju nam da koristimo nekoliko tehnika kako bismo imali koristi od funkcionalnog programiranja. U ovom ćemo odjeljku pokriti neke od ovih popularnih tehnika i razumjeti kako ih možemo implementirati u Javi.

4.1. Sastav funkcije

Sastav funkcije odnosi se na sastavljanje složenih funkcija kombiniranjem jednostavnijih funkcija. To se prije svega postiže u Javi pomoću funkcionalnih sučelja, koja su zapravo ciljni tipovi za lambda izraze i reference metoda.

Tipično, svako sučelje s jednom apstraktnom metodom može poslužiti kao funkcionalno sučelje. Stoga funkcionalno sučelje možemo definirati prilično jednostavno. Međutim, Java 8 prema zadanim postavkama nudi nam mnoga funkcionalna sučelja za različite slučajeve korištenja u paketu java.util.funkcija.

Mnoga od ovih funkcionalnih sučelja pružaju podršku za sastav funkcije u smislu zadano i statički metode. Idemo odabrati Funkcija sučelje da to bolje razumijemo. Funkcija je jednostavno i generičko funkcionalno sučelje koje prihvaća jedan argument i daje rezultat.

Također pruža dvije zadane metode, sastaviti i i onda, koji će nam pomoći u sastavu funkcija:

Dnevnik funkcija = (vrijednost) -> Math.log (vrijednost); Funkcija sqrt = (vrijednost) -> Math.sqrt (vrijednost); Funkcija logThenSqrt = sqrt.compose (dnevnik); logger.log (Level.INFO, String.valueOf (logThenSqrt.apply (3.14))); // Izlaz: 1,06 Funkcija sqrtThenLog = sqrt.andThen (zapisnik); logger.log (Level.INFO, String.valueOf (sqrtThenLog.apply (3.14))); // Izlaz: 0,57

Obje ove metode omogućuju nam da sastavimo više funkcija u jednu funkciju, ali nude različitu semantiku. Dok sastaviti prvo primjenjuje funkciju prosljeđenu u argumentu, a zatim funkciju na koju se poziva, i onda čini isto i obrnuto.

Ima nekoliko drugih funkcionalnih sučelja zanimljive metode za upotrebu u sastavu funkcija, kao što su zadane metode i, ili, i negirati u Predikat sučelje. Iako ta funkcionalna sučelja prihvaćaju jedan argument, postoje dvojake specijalizacije, poput BiFunction i BiPredicate.

4.2. Monade

Mnogi koncepti funkcionalnog programiranja potječu iz teorije kategorija, koja je opća teorija funkcija u matematici. Predstavlja nekoliko koncepata kategorija poput funktora i prirodnih transformacija. Za nas je važno samo znati da je to osnova korištenja monada u funkcionalnom programiranju.

Formalno, monada je apstrakcija koja omogućuje generičko strukturiranje programa. U osnovi, monada omogućuje nam omotavanje vrijednosti, primjenu skupa transformacija i vraćanje vrijednosti sa svim primijenjenim transformacijama. Naravno, postoje tri zakona koje bilo koja monada treba slijediti - lijevi identitet, desni identitet i asocijativnost - ali nećemo ulaziti u detalje.

U Javi postoji nekoliko monada koje koristimo prilično često, poput Neobvezno i Stream:

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

Sad, zašto zovemo Neobvezno monada? Ovdje, Neobvezno omogućuje nam umotavanje vrijednosti pomoću metode od i primijeniti niz transformacija. Primjenjujemo transformaciju dodavanja još jedne zamotane vrijednosti pomoću metode flatMap.

Ako želimo, to možemo pokazati Neobvezno slijedi tri zakona monada. Međutim, kritičari će brzo naglasiti da an Neobvezno u nekim okolnostima krši zakone o monadi. Ali, za većinu praktičnih situacija to bi trebalo biti dovoljno dobro za nas.

Ako razumijemo osnove monada, uskoro ćemo shvatiti da u Javi postoji mnogo drugih primjera, poput Stream i CompletableFuture. Pomažu nam u postizanju različitih ciljeva, ali svi imaju standardni sastav u kojem se upravlja manipulacijom ili transformacijom.

Naravno, možemo definirati vlastite vrste monada u Javi kako bismo postigli različite ciljeve poput monade dnevnika, monade izvještaja ili monade revizije. Sjećate se kako smo razgovarali o rukovanju nuspojavama u funkcionalnom programiranju? Pa, kako se čini, monada je jedna od tehnika funkcionalnog programiranja koja će to postići.

4.3. Currying

Currying je matematički tehnika pretvaranja funkcije koja uzima više argumenata u niz funkcija koje uzimaju jedan argument. Ali, zašto su nam potrebni u funkcionalnom programiranju? Daje nam moćnu tehniku ​​kompozicije u kojoj ne trebamo pozivati ​​funkciju sa svim njezinim argumentima.

Štoviše, karirana funkcija ne ostvaruje svoj učinak dok ne primi sve argumente.

U čisto funkcionalnim programskim jezicima kao što je Haskell, currying je dobro podržan. Zapravo su sve funkcije zadane. Međutim, u Javi to nije tako jednostavno:

Funkcija težina = masa -> gravitacija -> masa * gravitacija; Funkcija weightOnEarth = weight.apply (9.81); logger.log (Level.INFO, "Moja težina na Zemlji:" + weightOnEarth.apply (60.0)); Funkcija weightOnMars = weight.apply (3.75); logger.log (Level.INFO, "Moja težina na Marsu:" + weightOnMars.apply (60.0));

Ovdje smo definirali funkciju za izračunavanje naše težine na planetu. Iako naša masa ostaje ista, gravitacija ovisi o planetu na kojem se nalazimo. Mi može djelomično primijeniti funkciju donošenjem samo gravitacije kako bi se definirala funkcija za određeni planet. Štoviše, ovu djelomično primijenjenu funkciju možemo proslijediti kao argument ili povratnu vrijednost za proizvoljan sastav.

Currying ovisi o jeziku da pruži dvije temeljne značajke: lambda izrazi i zatvaranja. Lambda izrazi su anonimne funkcije koje nam pomažu da kod tretiramo kao podatke. Već smo vidjeli kako ih implementirati pomoću funkcionalnih sučelja.

Sad, lambda izraz može zatvoriti svoj leksički opseg, koji definiramo kao njegovo zatvaranje. Pogledajmo primjer:

privatna statička funkcija weightOnEarth () {konačna dvostruka gravitacija = 9,81; povratna masa -> masa * gravitacija; }

Napominjemo kako lambda izraz, koji smo vratili u gornjoj metodi, ovisi o priloženoj varijabli, koju nazivamo zatvaranjem. Za razliku od ostalih funkcionalnih programskih jezika, Java ima ograničenje da opseg koji obuhvaća mora biti konačan ili zapravo konačan.

Kao zanimljiv ishod, currying nam također omogućuje stvaranje funkcionalnog sučelja u Javi proizvoljnog arititeta.

4.4. Rekurzija

Rekurzija je još jedna moćna tehnika u funkcionalnom programiranju koja omogućuje nam da raščlanimo problem na manje dijelove. Glavna prednost rekurzije je ta što nam pomaže ukloniti nuspojave, što je tipično za bilo koji imperativni stil petljanja.

Pogledajmo kako izračunavamo faktorijel broja pomoću rekurzije:

Cjelobrojni faktorijel (Integer number) {return (number == 1)? 1: broj * faktorijel (broj - 1); }

Ovdje istu funkciju pozivamo rekurzivno dok ne dođemo do osnovnog slučaja i zatim počnemo računati svoj rezultat.Primijetite da vršimo rekurzivni poziv prije izračuna rezultata u svakom koraku ili riječima na čelu izračuna. Stoga, ovaj stil rekurzije poznat je i pod nazivom rekurzija glave.

Nedostatak ove vrste rekurzije je taj što svaki korak mora zadržati stanje svih prethodnih koraka dok ne dođemo do osnovnog slučaja. To zapravo nije problem za male brojeve, ali zadržavanje stanja za velike brojeve može biti neučinkovito.

Rješenje je a malo drugačija provedba rekurzije poznate kao repna rekurzija. Ovdje osiguravamo da rekurzivni poziv bude zadnji poziv koji funkcija uputi. Pogledajmo kako možemo prepisati gornju funkciju da bismo koristili rekurziju repa:

Cjelobrojni faktorijel (cijeli broj, rezultat cijelog broja) {return (number == 1)? rezultat: faktorijel (broj - 1, rezultat * broj); }

Primijetite upotrebu akumulatora u funkciji, eliminirajući potrebu zadržavanja stanja na svakom koraku rekurzije. Stvarna korist ovog stila je iskoristiti optimizacije kompajlera gdje kompajler može odlučiti pustiti okvir steka trenutne funkcije, tehniku ​​poznatu kao uklanjanje rep-poziva.

Iako mnogi jezici poput Scale podržavaju eliminaciju poziva, Java još uvijek nema podršku za to. Ovo je dio zaostataka za Javu i možda će se pojaviti u nekom obliku kao dio većih promjena predloženih u okviru Project Loom.

5. Zašto je važno funkcionalno programiranje?

Nakon dosadašnjeg prolaska kroz tutorial, moramo se zapitati zašto se uopće želimo toliko truditi. Za nekoga tko dolazi iz Java pozadine, pomak koji zahtjevi funkcionalnog programiranja nisu trivijalni. Dakle, trebalo bi postojati neke zaista obećavajuće prednosti usvajanja funkcionalnog programiranja u Javi.

Najveća prednost usvajanja funkcionalnog programiranja na bilo kojem jeziku, uključujući Javu, je čiste funkcije i nepromjenjiva stanja. Ako razmišljamo unatrag, većina programskih izazova na ovaj ili onaj način ukorijenjena je u nuspojavama i promjenjivim stanjima. Jednostavno ih se riješi čini naš program lakšim za čitanje, obrazloženje, testiranje i održavanje.

Deklarativno programiranje, kao takvo, dovodi do vrlo jezgrovitih i čitljivih programa. Funkcionalno programiranje, kao podskup deklarativnog programiranja, nudi nekoliko konstrukata poput funkcija višeg reda, sastava funkcija i lančanog funkcioniranja. Razmislite o prednostima koje je Stream API donio u Javu 8 za rukovanje podacima.

Ali nemojte doći u napast da se prebacite ako niste potpuno spremni. Imajte na umu da funkcionalno programiranje nije jednostavan obrazac dizajna koji možemo odmah koristiti i od kojeg možemo imati koristi. Funkcionalno programiranje je više promjena u načinu na koji razmišljamo o problemima i njihovim rješenjima i kako strukturirati algoritam.

Dakle, prije nego što počnemo koristiti funkcionalno programiranje, moramo se osposobiti za razmišljanje o našim programima u smislu funkcija.

6. Je li Java prikladan?

Iako je teško poreći prednosti funkcionalnog programiranja, ne možemo se ne zapitati je li Java prikladan izbor za nju. Povijesno gledano, Java se razvila kao programski jezik opće namjene pogodniji za objektno orijentirano programiranje. Čak je i razmišljanje o korištenju funkcionalnog programiranja prije Java 8 bilo zamorno! No stvari su se definitivno promijenile nakon Jave 8.

Sama činjenica da u Javi ne postoje istinski tipovi funkcija protivi se osnovnim načelima funkcionalnog programiranja. Funkcionalna sučelja u maskiranju lambda izraza to uglavnom nadoknađuju, barem sintaksički. Zatim, činjenica da vrste u Javi su u osnovi promjenjive i moramo napisati toliko uzorka da bismo stvorili nepromjenjive tipove, ne pomaže.

Od funkcionalnog programskog jezika očekujemo i druge stvari koje u Javi nedostaju ili su teške. Na primjer, zadana strategija procjene argumenata u Javi je nestrpljiva. No, lijeno vrednovanje učinkovitiji je i preporučljiviji način u funkcionalnom programiranju.

Još uvijek možemo postići lijenu procjenu u Javi koristeći kratki spoj operatora i funkcionalna sučelja, ali to je više uključeno.

Popis sigurno nije potpun i može sadržavati generičku podršku s brisanjem tipa, nedostajuću podršku za optimizaciju repnih poziva i druge stvari. Međutim, imamo široku ideju. Java definitivno nije prikladna za pokretanje programa od nule u funkcionalnom programiranju.

Ali što ako već imamo postojeći program napisan na Javi, vjerojatno u objektno orijentiranom programiranju? Ništa nas ne sprječava da dobijemo neke od prednosti funkcionalnog programiranja, posebno s Javom 8.

Tu se većina prednosti funkcionalnog programiranja krije za Java programera. Kombinacija objektno orijentiranog programiranja i blagodati funkcionalnog programiranja može uvelike ići.

7. Zaključak

U ovom uputstvu prošli smo kroz osnove funkcionalnog programiranja. Obradili smo temeljna načela i kako ih možemo usvojiti u Javi. Dalje, razgovarali smo o nekim popularnim tehnikama u funkcionalnom programiranju s primjerima na Javi.

Na kraju smo pokrili neke od prednosti usvajanja funkcionalnog programiranja i odgovorili je li Java prikladna za isto.

Izvorni kôd članka dostupan je na GitHubu.