Lambda výrazy v Kotline

1. Prehľad

V tomto článku sa chystáme preskúmať lambdas v jazyku Kotlin. Pamätajte, že lambdy nie sú pre Kotlina jedinečné a existujú už mnoho rokov v mnohých ďalších jazykoch.

Výrazy lambdas sú v podstate anonymné funkcie, ktoré môžeme považovať za hodnoty - môžeme ich napríklad odovzdať ako argumenty metódam, vrátiť ich alebo urobiť čokoľvek iné, čo by sme mohli urobiť s normálnym objektom.

2. Definovanie lambdy

Ako uvidíme, Kotlin Lambdas sú veľmi podobné Java Lambdas. Tu sa dozviete viac informácií o práci s Java Lambdas a niektoré osvedčené postupy.

Ak chcete definovať lambdu, musíme sa držať syntaxe:

val lambdaName: Type = {argumentList -> codeBody}

Jedinou časťou lambda, ktorá nie je voliteľná, je codeBody.

Zoznam argumentov je možné preskočiť, keď definujete najviac jeden argument a znak Typ sa dá často odvodiť z prekladača Kotlin. Nie vždy potrebujeme aj premennú, lambda sa dá odovzdať priamo ako argument metódy.

Typ posledného príkazu v rámci bloku lambda je vrátený typ.

2.1. Zadanie typu

Odvodenie typu Kotlin umožňuje kompilátoru vyhodnotiť typ lambda.

Písanie lambdy, ktorá vytvára druhú mocninu čísla, by vyzeralo takto:

val štvorec = {number: Int -> number * number} val deväť = štvorec (3)

Kotlin vyhodnotí vyššie uvedený príklad ako funkciu, ktorá ho vezme Int a vráti Int:(Int) -> Int

Ak by sme chceli vytvoriť lambdu, ktorá vynásobí počet jej jednotlivých argumentov číslom 100, vráti túto hodnotu ako a Reťazec:

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

Kotlin pochopí, že táto lambda je typová (Int) -> Reťazec.

2.2. Vyhlásenie typu

Kotlin príležitostne nemôže odvodiť naše typy a musíme výslovne deklarovať typ pre našu lambdu; rovnako ako môžeme pri akomkoľvek inom type.

Vzor je vstup -> výstup, ak však kód nevráti žiadnu hodnotu, použijeme typ Jednotka:

val that: Int -> Int = {three -> three}
viac: (String, Int) -> String = {str, int -> str + int}
val noReturn: Int -> Unit = {num -> println (num)}

Ako rozšírenie triedy môžeme použiť lambdas:

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

Vzor, ktorý tu používame, sa mierne líši od ostatných lambd, ktoré sme definovali. Naše zátvorky stále obsahujú naše argumenty, ale pred našimi zátvorkami máme typ, ku ktorému pripojíme túto lambdu.

Ak chcete použiť tento vzor z a String voláme Type.lambdaName (argumenty)aby sme nazvali náš „iný“ príklad:

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

2.3. Návrat z lambdy

Konečným výrazom je hodnota, ktorá sa vráti po vykonaní lambdy:

val countGrade = {grade: Int -> when (grade) {in 0..40 -> "Fail" in 41..70 -> "Pass" in 71..100 -> "Distinction" else -> false}}

Posledným spôsobom je využiť definíciu anonymnej funkcie - musíme explicitne definovať argumenty a typ návratu a príkaz návrat môžeme použiť rovnako ako ktorákoľvek iná metóda:

val countGrade = zábava (známka: Int): Reťazec {if (známka 100) {návrat "Chyba"} else if (známka <40) {návrat "Zlyhanie"} else if (známka <70) {návrat "Úspešné"} návrat „Rozlíšenie“}

3. to

Krátkou skratkou jedného argumentu lambda je použitie kľúčového slova „to '. Táto hodnota predstavuje akýkoľvek osamelý argument, ktorý odovzdáme funkcii lambda.

Vykonáme to isté pre každý metóda na nasledujúcom poli Ints:

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

Najprv sa pozrieme na dlhodobú formu funkcie lambda, po ktorej nasleduje skratková podoba toho istého kódu, kde ‘to‘Bude predstavovať každý prvok v nasledujúcom poli.

Longhand:

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

Skratka:

array.forEach {println (it * 4)}

4. Implementácia lambdas

Veľmi stručne sa budeme venovať tomu, ako nazvať lambdu, ktorá je v rozsahu pôsobnosti, a tiež ako podať lambdu ako argument.

Keď už je objekt lambda v rozsahu, zavolajte ho ako ktorúkoľvek inú metódu v rozsahu pomocou svojho názvu, za ktorým nasledujú zátvorky a akékoľvek argumenty:

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

Ak potrebujeme predať lambdu ako argument do metódy vyššieho rádu, máme päť možností.

4.1. Premenná objektu Lambda

Pomocou existujúceho objektu lambda, ako je deklarovaný v časti 2, odovzdáme objekt do metódy tak, ako by sme to urobili s akýmkoľvek iným argumentom:

@Test zábava whenPassingALambdaObject_thenCallTriggerLambda () {val lambda = {arg: Double -> arg == 4,329} výsledok val = invokeLambda (lambda) assertTrue (výsledok)}

4.2. Lambda Doslov

Namiesto toho, aby sme lambdu priradili k premennej, môžeme literál odovzdať priamo do volania metódy:

Vyskúšajte si zábavu whenPassingALambdaLiteral_thenCallTriggerLambda () {val result = invokeLambda ({true}) assertTrue (result)}

4.3. Lambda doslovne v zátvorkách

Ďalším vzorom pre literály lambda, ktorý podporuje JetBrains - je odovzdať lambda ako posledný argument metóde a umiestniť lambdu mimo volania metódy:

@Test zábava whenPassingALambdaLiteralOutsideBrackets_thenCallTriggerLambda () {val result = invokeLambda {arg -> arg.isNaN ()} assertFalse (result)}

4.4. Odkazy na metódu

Nakoniec máme možnosť použiť odkazy na metódy. Toto sú odkazy na existujúce metódy.

V našom príklade uvedenom nižšie si vezmeme Double :: isFinite. Táto funkcia potom nadobúda rovnakú štruktúru ako lambda, je však svojho typu Funkcia K keďže má jeden argument, prijíma a Dvojitý a vráti a Boolovský:

@Test zábava whenPassingAFunctionReference_thenCallTriggerLambda () {val referencia = Double :: isFinite val result = invokeLambda (reference) assertTrue (result)}

5. Kotlin Lambda v Jave

Kotlin používa generované funkčné rozhrania na spoluprácu s Javou. Tu existujú v zdrojovom kóde Kotlin.

Máme obmedzený počet argumentov, ktoré je možné vložiť do týchto generovaných tried. Aktuálny limit je 22; predstavuje rozhranie Funkcia22.

Štruktúra a Funkcia generické rozhranie je, že počet a predstavuje počet argumentov k lambda, potom tento počet tried bude argumentom Typy v poradí.

Posledným všeobecným argumentom je návratový typ:

import kotlin.jvm.functions. * verejné rozhranie Function1: Function {public operator fun invoke (p1: P1): R}

Ak v kóde Kotlin nie je definovaný žiadny návratový typ, potom lambda vráti Kotlin Jednotka. Kód Java musí importovať triedu z kotlin zabaliť a vrátiť s nulový.

Nižšie je uvedený príklad volania Kotlin Lambda z projektu, ktorý je súčasťou Kotlin a časť Java:

import kotlin.Unit; import kotlin.jvm.functions.Function1; ... new Function1 () {@Override public Unit invoke (Customer c) {AnalyticsManager.trackFacebookLogin (c.getCreated ()); návrat null; }} 

Pri použití Java8 používame namiesto a Funkcia anonymná trieda:

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

6. Anonymné vnútorné triedy

Kotlin má dva zaujímavé spôsoby práce s anonymnými vnútornými triedami.

6.1. Výraz objektu

Pri volaní vnútornej anonymnej triedy Kotlin alebo anonymnej triedy Java zloženej z viacerých metód musíme implementovať výraz objektu.

Aby sme to demonštrovali, vezmeme jednoduché rozhranie a triedu, ktorá prevezme implementáciu tohto rozhrania a zavolá metódy závislé od a Boolovský argument:

trieda Procesor {interface ActionCallback {fun success (): String fun failure (): String} fun performEvent (decision: Boolean, callback: ActionCallback): String {return if (decision) {callback.success ()} else {callback.failure ()}}}

Teraz, aby sme poskytli anonymnú vnútornú triedu, musíme použiť syntax „objektu“:

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

6.2. Lambda výraz

Na druhej strane môžeme mať tiež možnosť použiť namiesto toho lambdu. Používanie lambd namiesto anonymnej vnútornej triedy má určité podmienky:

  1. Trieda je implementáciou Java rozhrania (nie Kotlinského)
  2. rozhranie musí mať max

Ak sú obidve tieto podmienky splnené, môžeme namiesto nich použiť výraz lambda.

Samotná lambda bude mať toľko argumentov, koľko má jediná metóda rozhrania.

Bežným príkladom by bolo použitie lambda namiesto štandardnej Javy Spotrebiteľ:

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

7. Záver

Aj keď sú syntakticky podobné, Kotlin a Java lambdas sú úplne odlišné vlastnosti. Pri zacielení na Javu 6 musí Kotlin transformovať svoje lambdy na štruktúru, ktorú je možné využiť v rámci JVM 1.6.

Napriek tomu stále platia osvedčené postupy Java 8 lambdas.

Viac informácií o osvedčených postupoch lambda tu.

Útržky kódu, ako vždy, nájdete na GitHub.