Programavimas

Java programavimas su lambda išraiškomis

Techniniame pagrindiniame „JavaOne 2013“ pagrindiniame pranešime Markas Reinholdas, „Oracle“ „Java“ platformos grupės vyriausiasis architektas, apibūdino „lambda“ išraiškas kaip didžiausią „Java“ programavimo modelio atnaujinimą. kada nors. Nors lambda išraiškoms yra daugybė programų, šiame straipsnyje daugiausia dėmesio skiriama konkrečiam pavyzdžiui, kuris dažnai pasitaiko matematinėse programose; būtent poreikis perduoti funkciją algoritmui.

Būdamas žilaplaukis geekas per daugelį metų programavau daugybe kalbų ir nuo 1.1 versijos plačiai programavau „Java“. Kai pradėjau dirbti su kompiuteriais, beveik niekas nebuvo baigęs informatikos mokslų. Kompiuterių profesionalai daugiausia buvo iš kitų sričių, tokių kaip elektrotechnika, fizika, verslas ir matematika. Ankstesniame gyvenime buvau matematikas, todėl nieko keista, kad mano pradinis kompiuterio vaizdas buvo milžiniškas programuojamas skaičiuotuvas. Per daugelį metų aš labai išplėtiau savo požiūrį į kompiuterius, bet vis tiek džiaugiuosi galimybe dirbti su programomis, kurios apima tam tikrą matematikos aspektą.

Daugelis matematikos programų reikalauja, kad funkcija būtų perduota kaip parametras algoritmui. Kolegijos algebros ir pagrindinio skaičiavimo pavyzdžiai yra lygties sprendimas arba funkcijos integralo apskaičiavimas. Daugiau nei 15 metų „Java“ buvo mano pasirinkta programavimo kalba daugumai programų, tačiau tai buvo pirmoji dažnai naudojama kalba, kuri neleido man perduoti funkcijos (techniškai žymiklio ar nuorodos į funkciją) kaip parametrą paprastai ir paprastai. Šis trūkumas netrukus pasikeis, kai bus išleista „Java 8“.

„Lambda“ išraiškų galia viršija vienkartinio naudojimo atvejus, tačiau, tiriant įvairius to paties pavyzdžio variantus, turėtumėte suprasti, kaip „lambdas“ bus naudinga jūsų „Java“ programoms. Šiame straipsnyje aš naudosiu įprastą pavyzdį, kuris padės apibūdinti problemą, tada pateiksiu sprendimus, parašytus C ++, „Java“ prieš „lambda“ išraiškas ir „Java“ su „lambda“ išraiškomis. Atkreipkite dėmesį, kad norint suprasti ir įvertinti pagrindines šio straipsnio nuostatas, nebūtina turėti tvirtos matematikos žinios.

Sužinokite apie lambdas

„Lambda“ posakiai, dar vadinami uždarymo, funkcijų pažodžiui ar tiesiog „lambdas“, apibūdina funkcijų rinkinį, apibrėžtą „Java Specification Request“ (JSR) 335. Mažiau oficialūs / lengviau skaitomi lambda posakių įvadai pateikiami naujausios versijos skyriuje. „Java Tutorial“ ir keliuose Briano Goetzo straipsniuose „Lambda būklė“ ir „Lambda būsena: bibliotekų leidimas“. Šie šaltiniai apibūdina lambda išraiškų sintaksę ir pateikia naudojimo atvejų, kai lambda išraiškos yra taikomos, pavyzdžius. Norėdami sužinoti daugiau apie „lambda“ išraiškas „Java 8“, žiūrėkite Marko Reinholdo techninį pagrindinį „JavaOne 2013“ adresą.

Lambda išraiškos matematiniame pavyzdyje

Šiame straipsnyje naudojamas pavyzdys yra Simpsono taisyklė iš pagrindinio skaičiavimo. „Simpson“ taisyklė arba, tiksliau, „Composite Simpson“ taisyklė, yra skaitmeninė integravimo technika, skirta apytiksliai apibrėžtam integralui. Nesijaudinkite, jei nesate susipažinę su a apibrėžtas integralas; ką jūs iš tikrųjų turite suprasti, yra tai, kad „Simpson“ taisyklė yra algoritmas, apskaičiuojantis realų skaičių pagal keturis parametrus:

  • Funkcija, kurią norime integruoti.
  • Du realūs skaičiai a ir b kurie atspindi intervalo taškus [a, b] tikrojo skaičiaus eilutėje. (Atkreipkite dėmesį, kad aukščiau nurodyta funkcija šiame intervale turėtų būti nepertraukiama.)
  • Lyginis sveikasis skaičius n tai nurodo daugybę subintervalų. Įgyvendindami Simpsono taisyklę, mes padalijame intervalą [a, b] į n subintervalai.

Norėdami supaprastinti pristatymą, sutelkime dėmesį į programavimo sąsają, o ne į įgyvendinimo detales. (Tiesą sakant, tikiuosi, kad šis metodas leis apeiti argumentus apie geriausią ar efektyviausią būdą įgyvendinti Simpsono taisyklę, kuri nėra šio straipsnio tema.) Mes naudosime tipą dvigubai parametrams a ir b, ir mes naudosime tipą tarpt parametrui n. Integruotai funkcijai reikės vieno tipo parametro dvigubai ir grąžina tipo vertę dvigubai.

Atsisiųsti Atsisiųskite šio straipsnio C ++ šaltinio kodo pavyzdį. Sukūrė Johnas I. Moore'as, skirtas „JavaWorld“

Funkcijos parametrai C ++

Norėdami pateikti palyginimo pagrindą, pradėkime nuo C ++ specifikacijos. Perduodamas funkciją kaip parametrą C ++, aš dažniausiai norėčiau nurodyti funkcijos parametro parašą naudodamas a typedef. 1 sąraše rodomas C ++ antraštės failas, pavadintas simpson.h kad nurodo tiek typedef funkcijos parametrui ir C ++ funkcijos pavadinimo programavimo sąsajai integruotis. Funkcijos kūnas integruotis yra C ++ šaltinio kodo faile, pavadintame simpson.cpp (neparodytas) ir pateikia „Simpson“ taisyklės įgyvendinimą.

Sąrašas 1. Simpsono taisyklės C ++ antraštės failas

 #if! define (SIMPSON_H) #define SIMPSON_H #įtraukti naudojant vardų srities standartą; typedef double DoubleFunction (dvigubas x); dvigubas integravimas („DoubleFunction f“, dvigubas a, dvigubas b, int n) metimas (invalid_argument); #endif 

Skambinama integruotis yra nesudėtinga C ++. Tarkime, kad kaip paprastą pavyzdį norėjote apipavidalinti „Simpson“ taisyklę sinusas funkcija nuo 0 iki π (PI) naudojant 30 subintervalai. (Kiekvienas, kuris baigė skaičiavimą, turėčiau sugebėti tiksliai apskaičiuoti atsakymą be skaičiuoklės pagalbos, todėl tai būtų geras integruotis funkcija.) Darant prielaidą, kad turėjote įskaitant tinkamus antraštės failus, tokius kaip ir "simpson.h", galėtumėte iškviesti funkciją integruotis kaip parodyta 2 sąraše.

Sąrašas 2. C ++ kvietimas integruoti funkciją

 dvigubas rezultatas = integruoti (sin, 0, M_PI, 30); 

Tai viskas. C ++ programoje jūs praeinate sinusas veikia taip pat lengvai, kaip perduodate kitus tris parametrus.

Kitas pavyzdys

Vietoj „Simpson“ taisyklės aš taip pat lengvai galėčiau naudoti „Bisection“ metodą (dar žinomas Bisection Algorithm) formos lygčiai išspręsti f (x) = 0. Tiesą sakant, šio straipsnio šaltinio kodas apima paprastą Simpsono taisyklės ir dalijimo metodo įgyvendinimą.

Atsisiųsti Atsisiųskite šio straipsnio „Java“ šaltinio kodo pavyzdžius. Sukūrė Johnas I. Moore'as, skirtas „JavaWorld“

Java be lambda posakių

Dabar pažiūrėkime, kaip „Simpson“ taisyklė gali būti nurodyta „Java“. Nepriklausomai nuo to, ar naudojame lambda išraiškas, vietoj C ++ naudojame „Java“ sąsają, parodytą 3 sąraše. typedef nurodyti funkcijos parametro parašą.

Sąrašas 3. Funkcijos parametro „Java“ sąsaja

 viešoji sąsaja „DoubleFunction“ {viešoji dviguba f (dviguba x); } 

Norėdami įgyvendinti „Simpson“ taisyklę „Java“, mes sukuriame klasę pavadinimu Simpsonas kuriame yra metodas, integruotis, turėdami keturis parametrus, panašius į tai, ką darėme C ++. Kaip ir naudojant daugybę savarankiškų matematinių metodų (žr., Pvz., java.lang.Math), mes padarysime integruotis statinis metodas. Metodas integruotis nurodoma taip:

Sąrašas 4. „Java“ parašas, skirtas integruoti „Simpson“ klasėje

 viešasis statinis dvigubas integravimas („DoubleFunction df“, „double a“, „double b“, „int n“) 

Viskas, ką iki šiol darėme „Java“, nepriklauso nuo to, ar naudosime „lambda“ išraiškas, ar ne. Pagrindinis skirtumas tarp lambda išraiškų yra tai, kaip mes perduodame parametrus (tiksliau, kaip mes perduodame funkcijos parametrą) kvietime į metodą integruotis. Pirmiausia parodysiu, kaip tai būtų daroma „Java“ versijose iki 8 versijos; y., be lambda posakių. Kaip ir C ++ pavyzdyje, tarkime, kad mes norime apytiksliai įvertinti integralą sinusas funkcija nuo 0 iki π (PI) naudojant 30 subintervalai.

„Adapter“ modelio naudojimas sinuso funkcijai

„Java“ sistemoje turime sinusas funkcija prieinama java.lang.Math, tačiau naudojant „Java“ versijas prieš „Java 8“, nėra paprasto, tiesioginio būdo tai perduoti sinusas metodo funkciją integruotis klasėje Simpsonas. Vienas iš būdų yra naudoti „Adapter“ modelį. Tokiu atveju parašytume paprastą adapterių klasę, kuri įgyvendina „DoubleFunction“ sąsają ir pritaiko ją skambinti sinusas funkcija, kaip parodyta 5 sąraše.

Sąrašas 5. Adapterio klasė metodui Math.sin

 importuoti com.softmoore.math.DoubleFunction; viešoji klasė „DoubleFunctionSineAdapter“ įgyvendina „DoubleFunction“ {public double f (double x) {return Math.sin (x); }} 

Naudodami šią adapterių klasę, dabar galime skambinti integruotis klasės metodas Simpsonas kaip parodyta 6 sąraše.

Sąrašas 6. Adapterio klasės naudojimas skambinant metodui „Simpson.integrate“

 „DoubleFunctionSineAdapter sine“ = naujas „DoubleFunctionSineAdapter“ (); dvigubas rezultatas = Simpson.integrate (sinusas, 0, Math.PI, 30); 

Sustabdykime akimirką ir palyginkime, ko reikėjo norint paskambinti integruotis C ++, palyginti su tuo, ko reikėjo ankstesnėse „Java“ versijose. Su C ++ mes tiesiog paskambinome integruotis, perduodamas keturis parametrus. Naudodami „Java“ turėjome sukurti naują adapterių klasę, o po to šią klasę iš karto užmegzti, kad galėtume skambinti. Jei norėtume integruoti kelias funkcijas, kiekvienai iš jų turėtume parašyti adapterio klasę.

Galėtume sutrumpinti kodą, reikalingą skambinti integruotis šiek tiek iš dviejų „Java“ sakinių į vieną, sukurdami naują adapterių klasės egzempliorių kvietime integruotis. Anoniminės klasės naudojimas, o ne atskiros adapterių klasės sukūrimas būtų dar vienas būdas šiek tiek sumažinti bendras pastangas, kaip parodyta 7 sąraše.

Sąrašas 7. Anoniminės klasės naudojimas skambinant metodui Simpson.integrate

 DoubleFunction sineAdapter = new DoubleFunction () {public double f (double x) {return Math.sin (x); }}; dvigubas rezultatas = Simpson.integrate (sineAdapter, 0, Math.PI, 30); 

Be „lambda“ išraiškų, 7 sąraše matote apie mažiausią kodo kiekį, kurį galėtumėte parašyti „Java“, kad paskambintumėte integruotis metodas, tačiau jis vis tiek yra daug sudėtingesnis, nei buvo reikalaujama C ++. Aš taip pat nesu patenkinta naudodama anoniminius užsiėmimus, nors anksčiau juos naudojau daug. Aš nemėgstu sintaksės ir visada maniau, kad tai nerangus, bet būtinas „Java“ įsilaužimas.

„Java“ su „lambda“ išraiškomis ir funkcinėmis sąsajomis

Dabar pažiūrėkime, kaip galėtume naudoti „Java“ išraiškas „Java 8“, kad supaprastintumėte skambutį integruotis Java. Nes sąsaja „DoubleFunction“ reikalingas tik vieno metodo įgyvendinimas, jis yra kandidatas į lambda išraiškas. Jei iš anksto žinome, kad naudosime lambda išraiškas, galime sąsają komentuoti @ Funkcinė sąsaja, nauja „Java 8“ anotacija, kurioje sakoma, kad turime funkcinė sąsaja. Atkreipkite dėmesį, kad šios anotacijos nereikia, tačiau tai suteikia mums papildomą patikrinimą, ar viskas yra nuosekliai, panašiai kaip @ Nepaisyti anotacija ankstesnėse „Java“ versijose.

Lambda išraiškos sintaksė yra argumentų sąrašas, uždarytas skliausteliuose, rodyklės ženklas (->) ir funkcinį kūną. Kūnas gali būti sakinių blokas (uždarytas petnešomis) arba vienas posakis. 8 sąraše rodoma lambda išraiška, įgyvendinanti sąsają „DoubleFunction“ ir tada perduodamas metodui integruotis.

8. Lambda išraiškos naudojimas norint paskambinti metodui Simpson.integrate

 „DoubleFunction“ sinusas = (dvigubas x) -> Math.sin (x); dvigubas rezultatas = Simpson.integrate (sinusas, 0, Math.PI, 30); 

Atkreipkite dėmesį, kad mums nereikėjo rašyti adapterio klasės ar kurti anoniminės klasės egzemplioriaus. Taip pat atkreipkite dėmesį, kad aukščiau išvardintus dalykus galėjome parašyti viename sakinyje, pakeisdami pačią lambda išraišką, (dvigubas x) -> Math.sin (x)parametrui sinusas antrame aukščiau pateiktame teiginyje, pašalindamas pirmąjį teiginį. Dabar mes artėjame prie paprastos sintaksės, kurią turėjome C ++. Bet palauk! Yra dar daugiau!

Funkcinės sąsajos pavadinimas nėra „lambda“ išraiškos dalis, tačiau jį galima spręsti remiantis kontekstu. Tipas dvigubai nes lambda išraiškos parametrą taip pat galima spręsti iš konteksto. Galiausiai, jei lambda išraiškoje yra tik vienas parametras, skliaustus galime praleisti. Taigi mes galime sutrumpinti kodą skambinti metodą integruotis į vieną kodo eilutę, kaip parodyta 9 sąraše.

Sąrašas 9. Alternatyvus lambda išraiškos formatas skambinant į Simpson.integrate

 dvigubas rezultatas = Simpson.integrate (x -> Math.sin (x), 0, Math.PI, 30); 

Bet palauk! Yra dar daugiau!

Metodo nuorodos „Java 8“

Kita susijusi „Java 8“ funkcija yra tai, kas vadinama a metodo nuoroda, kuris leidžia mums įvardyti esamą metodą vardu. Metodo nuorodos gali būti naudojamos vietoje lambda išraiškų, jei jos atitinka funkcinės sąsajos reikalavimus. Kaip aprašyta šaltiniuose, yra keletas skirtingų metodų nuorodų, kurių kiekviena turi šiek tiek skirtingą sintaksę. Statinių metodų sintaksė yra „Classname :: methodName“. Todėl, naudodami metodo nuorodą, galime iškviesti integruotis metodą „Java“ taip paprastai, kaip galėtume „C ++“. Palyginkite „Java 8“ skambutį, parodytą žemiau esančiame 10 sąraše, su originaliu „C ++“ skambučiu, parodytu aukščiau esančiame 2 sąraše.

Sąrašas 10. Naudojant metodo nuorodą paskambinti Simpson.integrate

 dvigubas rezultatas = Simpson.integrate (Math :: sin, 0, Math.PI, 30); 
$config[zx-auto] not found$config[zx-overlay] not found