Lambda izrazi u Kotlinu

1. Pregled

U ovom ćemo članku istraživati ​​Lambde na jeziku Kotlin. Imajte na umu da lambda nije jedinstvena za Kotlin i postoji već dugi niz godina na mnogim drugim jezicima.

Lambdas izrazi su u osnovi anonimne funkcije koje možemo tretirati kao vrijednosti - možemo ih, na primjer, proslijediti kao argumente metodama, vratiti ih ili učiniti bilo što drugo što bismo mogli učiniti s normalnim objektom.

2. Utvrđivanje Lambde

Kao što ćemo vidjeti, Kotlin Lambdas vrlo su slični Java Lambdama. Ovdje možete saznati više o radu s Java Lambdas i nekim najboljim praksama.

Da bismo definirali lambdu, moramo se pridržavati sintakse:

val lambdaName: Upišite = {argumentList -> codeBody}

Jedini dio lambde koji nije neobavezan je codeBody.

Popis argumenata može se preskočiti kada se definira najviše jedan argument i Tip često može zaključiti Kotlinov kompajler. Ne trebaju nam uvijek i varijable, lambda se može izravno proslijediti kao argument metode.

Tip posljednje naredbe unutar lambda bloka je vraćeni tip.

2.1. Tip zaključivanje

Kotlinovo zaključivanje tipa omogućuje kompajlatoru da ocjeni vrstu lambde.

Zapisivanje lambde koja stvara kvadrat broja bilo bi napisano kao:

val kvadrat = {broj: Int -> broj * broj} val devet = kvadrat (3)

Kotlin će gornji primjer procijeniti kao funkciju koja ga uzima Int i vraća an Int:(Int) -> Int

Ako smo željeli stvoriti lambdu koja množi pojedinačne brojeve argumenata sa 100, tada vraća tu vrijednost kao a Niz:

val magnitude100String = {input: Int -> val magnitude = input * 100 magnitude.toString ()} 

Kotlin će razumjeti da je ova lambda tipa (Int) -> Niz.

2.2. Izjava o tipu

Povremeno Kotlin ne može zaključiti naše vrste i moramo izričito deklarirati tip za našu lambdu; baš kao što možemo i s bilo kojom drugom vrstom.

Uzorak je ulaz -> izlaz, međutim, ako kod ne vrati vrijednost, koristimo tip Jedinica:

val koji: Int -> Int = {tri -> tri}
val više: (String, Int) -> String = {str, int -> str + int}
val noReturn: Int -> Jedinica = {num -> println (num)}

Lambde možemo koristiti kao nastavke razreda:

val drugi: String. (Int) -> String = {this + it}

Uzorak koji ovdje koristimo malo se razlikuje od ostalih lambda koje smo definirali. Naše zagrade i dalje sadrže naše argumente, ali prije zagrada imamo tip kojem ćemo priložiti ovu lambdu.

Da biste koristili ovaj obrazac iz a Niz nazivamo Type.lambdaName (argumenti)pa nazvati naš 'drugi' primjer:

zabavno extensionString (arg: String, num: Int): String {val drugi: String. (Int) -> String = {this + it} return arg.another (num)}

2.3. Povratak s Lambde

Konačni izraz je vrijednost koja će se vratiti nakon izvršavanja lambda-a:

val izračunajGrade = {ocjena: Int -> kada (ocjena) {u 0..40 -> "Fail" u 41..70 -> "Pass" u 71..100 -> "Distinction" else -> false}}

Konačni način je iskoristiti definiciju anonimne funkcije - moramo eksplicitno definirati argumente i tip povratka i možemo koristiti izraz return kao i bilo koja metoda:

val izračunajGrade = zabava (ocjena: Int): Niz {if (ocjena 100) {return "Pogreška"} else if (ocjena <40) {return "Fail"} else if (ocjena <70) {return "Pass"} return "Distinkcija"}

3. to

Skraćenica jednog argumenta lambda je uporaba ključne riječi ‘to'. Ova vrijednost predstavlja bilo koji usamljeni argument koji prosljeđujemo lambda funkciji.

Izvest ćemo isto za svakoga metoda na sljedećem nizu Ints:

val niz = arrayOf (1, 2, 3, 4, 5, 6)

Prvo ćemo pogledati stenografski oblik lambda funkcije, nakon čega slijedi stenografski oblik istog koda, gdje 'to’Predstavljat će svaki element u sljedećem nizu.

Običan rukopis:

array.forEach {item -> println (item * 4)}

Stenografija:

array.forEach {println (it * 4)}

4. Primjena Lambda

Vrlo ćemo kratko opisati kako nazvati lambdu koja je u opsegu, kao i kako proslijediti lambdu kao argument.

Jednom kada je lambda objekt u opsegu, pozovite ga kao bilo koju drugu metodu u opsegu, koristeći njegovo ime nakon kojeg slijede zagrade i svi argumenti:

zabava invokeLambda (lambda: (Double) -> Boolean): Boolean {return lambda (4.329)}

Ako trebamo proslijediti lambdu kao argument u metodu višeg reda, imamo pet mogućnosti.

4.1. Varijabla Lambda objekta

Koristeći postojeći lambda objekt kako je deklarirano u odjeljku 2, prosljeđujemo objekt u metodu kao i kod bilo kojeg drugog argumenta:

@Test zabave whenPassingALambdaObject_thenCallTriggerLambda () {val lambda = {arg: Double -> arg == 4.329} val rezultat = invokeLambda (lambda) assertTrue (rezultat)}

4.2. Lambda doslovno

Umjesto da lambdu dodijelimo varijabli, doslovce možemo proslijediti izravno u poziv metode:

Testirajte zabavu whenPassingALambdaLiteral_thenCallTriggerLambda () {val rezultat = invokeLambda ({true}) assertTrue (rezultat)}

4.3. Lambda doslovno izvan zagrada

Sljedeći obrazac za lambda-literale koje potiče JetBrains - je prosljeđivanje lambde kao posljednjeg argumenta metodi i postavljanje lambde izvan poziva metode:

@Test zabave whenPassingALambdaLiteralOutsideBrackets_thenCallTriggerLambda () {val result = invokeLambda {arg -> arg.isNaN ()} assertFalse (rezultat)}

4.4. Reference o metodama

Napokon, imamo mogućnost korištenja referenci metoda. To su reference na postojeće metode.

U našem donjem primjeru uzimamo Double :: isFinite. Ta funkcija tada poprima istu strukturu kao i lambda, međutim, ona je tipa KFunkcija1 kako ima jedan argument, uzima u Dvostruko i vraća a Booleova:

@Test zabave whenPassingAFunctionReference_thenCallTriggerLambda () {val reference = Double :: isFinite val rezultat = invokeLambda (referenca) assertTrue (rezultat)}

5. Kotlin Lambda u Javi

Kotlin koristi generirana sučelja funkcija za interakciju s Javom. Ovdje postoje u izvornom kodu Kotlin.

Imamo ograničenje broja argumenata koji se mogu proslijediti s ovim generiranim klasama. Trenutna granica je 22; predstavljen sučeljem Funkcija22.

Struktura a Funkcija Generički prikaz sučelja je da broj i predstavlja broj argumenata lambda, tada će taj broj klasa biti Tipovi argumenata redom.

Konačni generički argument je vrsta povrata:

uvoz kotlin.jvm.functions. * javno sučelje Funkcija1: Funkcija {javni poziv operatora za zabavu (p1: P1): R}

Kada unutar Kotlinovog koda nije definiran tip povrata, tada lambda vraća Kotlin Jedinica. Java kôd mora uvesti klasu iz kotlin paket i povratak sa null.

Ispod je primjer pozivanja Kotlin Lambde iz projekta koji je dio Kotlin i dio Java:

uvoz kotlin.Unit; uvoz kotlin.jvm.functions.Function1; ... nova Funkcija1 () {@Override pozivanje javne jedinice (kupac c) {AnalyticsManager.trackFacebookLogin (c.getCreated ()); return null; }} 

Kada koristimo Java8, umjesto a. Koristimo Java lambda Funkcija anonimni razred:

@Test void givenJava8_whenUsingLambda_thenReturnLambdaResult () {assertTrue (LambdaKt.takeLambda (c -> c> = 0)); }

6. Anonimni unutarnji tečajevi

Kotlin ima dva zanimljiva načina rada s anonimnim unutarnjim klasama.

6.1. Izražavanje predmeta

Kada pozivamo Kotlinovu unutarnju anonimnu klasu ili Java anonimnu klasu koja se sastoji od više metoda, moramo implementirati Object Expression.

Da bismo to demonstrirali, uzet ćemo jednostavno sučelje i klasu koja uzima implementaciju tog sučelja i poziva metode ovisne o a Booleova argument:

klasa Procesor {sučelje ActionCallback {zabavan uspjeh (): String zabavni neuspjeh (): String} zabavno performEvent (odluka: Boolean, povratni poziv: ActionCallback): Niz {return if (odluka) {callback.success ()} else {callback.failure ()}}}

Sada da bismo pružili anonimnu unutarnju klasu, trebamo koristiti sintaksu "objekt":

@Test fun givenMultipleMethods_whenCallingAnonymousFunction_thenTriggerSuccess () {val result = Processor (). PerformEvent (true, object: Processor.ActionCallback {override fun success () = "Success" override fun failure () = "Failure"}) assertEquals ("Success", "Success") rezultat)}

6.2. Lambda Izraz

S druge strane, možda imamo i mogućnost korištenja lambde. Korištenje lambda umjesto anonimne unutarnje klase ima određene uvjete:

  1. Klasa je implementacija Java sučelja (a ne Kotlina)
  2. sučelje mora imati maks

Ako su oba ova uvjeta zadovoljena, umjesto toga možemo upotrijebiti lambda izraz.

Sama lambda će uzeti onoliko argumenata koliko i pojedinačna metoda sučelja.

Uobičajeni primjer bio bi korištenje lambde umjesto standardne Jave Potrošač:

val list = ArrayList (2) list.stream () .forEach ({i -> println (i)})

7. Zaključak

Iako su sintaksički slične, lambda Kotlin i Java potpuno su različite značajke. Kada cilja Javu 6, Kotlin mora transformirati svoje lambdase u strukturu koja se može koristiti unutar JVM 1.6.

Unatoč tome, i dalje vrijede najbolji postupci rada s Java 8 lambdama.

Više o najboljim praksama lambda ovdje.

Isječci koda, kao i uvijek, mogu se naći na GitHubu.