Metode produženja u Kotlinu

1. Uvod

Kotlin uvodi koncept metoda produženja - koje su praktičan način proširivanja postojećih klasa novom funkcionalnošću bez korištenja nasljedstva ili bilo kakvih oblika uzorka Decorator - nakon definiranja produžetka. u osnovi ga možemo koristiti - jer je to bio dio izvornog API-ja.

Ovo može biti vrlo korisno za olakšavanje čitanja i održavanja našeg koda, jer možemo dodati metode koje su specifične za naše potrebe i čine se da su dio izvornog koda, čak i kad nemamo pristup izvori.

Na primjer, možda ćemo trebati izvesti XML bijeg na a Niz. U standardni Java kôd trebali bismo napisati metodu koja to može izvesti i nazvati je:

Niz je pobjegao = escapeStringForXml (ulaz);

Dok je ispisan u Kotlinu, isječak se može zamijeniti sa:

val pobjegao = input.escapeForXml ()

Ne samo da je ovo lakše čitati, već će IDE-ovi moći metodu ponuditi kao mogućnost samodovršavanja, isto kao da je to standardna metoda na Niz razred.

2. Standardne metode proširenja knjižnice

Standardna knjižnica Kotlin isporučuje se s nekim metodama proširenja odmah.

2.1. Prilagođavanje konteksta metodama produženja

Postoje neka generička proširenja koja se mogu primijeniti na sve vrste u našoj aplikaciji. Oni se mogu koristiti kako bi se osiguralo da se kôd izvodi u odgovarajućem kontekstu, a u nekim slučajevima i za osiguranje da varijabla nije null.

Ispada da, najvjerojatnije, koristimo proširenja, a da to nismo svjesni.

Jedan od najpopularnijih možda je neka () metoda, koja se može pozvati na bilo kojem tipu u Kotlinu - proslijedimo joj funkciju koja će se izvršiti na početnoj vrijednosti:

val name = "Baeldung" val velika slova = name .let {n -> n.toUpperCase ()}

Slično je karta() metoda iz Neobvezno ili Stream klase - u ovom slučaju prenosimo funkciju koja predstavlja radnju koja pretvara zadani Niz u njegov gornji prikaz.

Varijabla Ime je poznat kao primatelj poziva jer je to varijabla na koju djeluje metoda produženja.

Ovo izvrsno funkcionira s operatorom sigurnog poziva:

val ime = moždaGetName () val velika slova = ime? .let {n -> n.toUpperCase ()}

U ovom je slučaju blok prešao na neka () izračunava se samo ako je varijabla Ime nije bilo ništavno. To znači da je unutar bloka vrijednost n zajamčeno je da nije null. Više o ovome ovdje.

Postoje i druge alternative za neka () to može biti korisno, ovisno o našim potrebama.

The trčanje() produžetak radi isto kao i neka (), ali prijemnik je predviđen kao ovaj vrijednost unutar pozvanog bloka:

val name = "Baeldung" val velika slova = name.run {toUpperCase ()}

primijeniti () radi isto kao i trčanje(), ali vraća prijemnik umjesto da vraća vrijednost iz navedenog bloka.

Iskoristimo primijeniti () za lančano pozivanje:

val languages ​​= mutableListOf () languages.apply {add ("Java") add ("Kotlin") add ("Groovy") add ("Python")} .apply {remove ("Python")} 

Primijetite kako naš kod postaje sažetiji i izražajniji bez potrebe za izričitom upotrebom ovaj ili to.

Također () produžetak radi baš kao neka (), ali vraća prijemnik na isti način kao i primijeniti () radi:

val languages ​​= mutableListOf () languages.also {popis -> list.add ("Java") list.add ("Kotlin") list.add ("Groovy")} 

The takeIf () ekstenzija je opremljena predikatom koji djeluje na prijamnik i ako se ovaj predikat vrati pravi zatim vraća prijamnik ili null u suprotnom - ovo djeluje slično kombinaciji kombinacije uobičajene karte() i filtar() metode:

val jezik = getLanguageUsed () val coolLanguage = language.takeIf {l -> l == "Kotlin"} 

TakeUnless () produženje je isto kao takeIf () ali s obrnutom logikom predikata.

val jezik = getLanguageUsed () val oldLanguage = language.takeUnless {l -> l == "Kotlin"} 

2.2. Metode produženja za zbirke

Kotlin dodaje velik broj metoda proširenja u standardne Java zbirke što može olakšati rad s našim kodom.

Te se metode nalaze unutra _Collections.kt, _Ranges.kt, i _Sekvence.kt, kao i _Arrays.kt za ekvivalentne metode na koje se primjenjuju Nizovi umjesto toga. (Zapamtite da su u Kotlinu Nizovi može se tretirati isto kao Zbirke)

Previše je ovih metoda proširenja za raspravu ovdje, zato pregledajte ove datoteke da biste vidjeli što je dostupno.

Uz Zbirke, Kotlin dodaje značajan broj metoda proširenja na Niz razred - definirano u _Strings.kt. Oni nam omogućuju liječenje Žice kao da su zbirke likova.

Sve ove metode proširenja djeluju zajedno kako bi nam omogućile da napišemo znatno čišće i lakše održavanje koda bez obzira na vrstu zbirke s kojom radimo.

3. Pisanje naših metoda produženja

Pa, što ako trebamo proširiti klasu novom funkcijom - bilo iz Java ili Kotlin Standard Library ili iz ovisne knjižnice koju koristimo?

Metode produženja napisane su kao i bilo koja druga metoda, ali klasa prijemnika je navedena kao dio imena funkcije, odvojena točkom.

Na primjer:

zabavno String.escapeForXml (): Niz {....}

Ovo će definirati novu funkciju koja se zove escapeForXml kao produžetak Niz klase, dopuštajući nam da ga zovemo kako je gore opisano.

Unutar ove funkcije prijemniku možemo pristupiti pomoću ovaj, isto kao da smo ovo napisali u Niz sama klasa:

fun String.escapeForXml (): String {return this .replace ("&", "&") .replace ("<", "", ">")}

3.1. Pisanje generičkih metoda produženja

Što ako želimo napisati metodu proširenja koja bi trebala biti primijenjena na više tipova, općenito? Mogli bismo samo produžiti Bilo koji type, - što je ekvivalent Objekt klase u Javi - ali postoji bolji način.

Metode produženja mogu se primijeniti na generički prijamnik kao i na konkretni:

zabava T.concatAsString (b: T): String {return this.toString () + b.toString ()}

To se može primijeniti na bilo koji tip koji udovoljava generičkim zahtjevima i unutar funkcije ovaj vrijednost je sigurna.

Na primjer, koristeći gornji primjer:

5.concatAsString (10) // kompajlira "5" .concatAsString ("10") // kompajlira 5.concatAsString ("10") // ne kompajlira

3.2. Pisanje metoda Infix produženja

Infix metode korisne su za pisanje koda u DSL stilu, jer omogućuju pozivanje metoda bez točke i zagrada:

infix zabava Number.toPowerOf (eksponent: Number): Double {return Math.pow (this.toDouble (), exponent.toDouble ())}

Sada to možemo nazvati jednako kao i bilo koji drugi način infiksa:

3 toPowerOf 2 // 9 9 toPowerOf 0,5 // 3

3.3. Pisanje metoda produženja operatora

Također bismo mogli napisati metodu operatora kao proširenje.

Operatorske metode su one koje nam omogućavaju da iskoristimo skraćenicu operatora umjesto punog naziva metode - npr. plus metoda operatora može se pozvati pomoću + operater:

operator zabava List.times (od: Int): List {return this.map {it * by}}

Opet, ovo djeluje na isti način kao i bilo koja druga metoda operatora:

listOf (1, 2, 3) * 4 // [4, 8, 12]

4. Pozivanje funkcije Kotlin Extension s Jave

Pogledajmo sada kako Java funkcionira s funkcijama Kotlin ekstenzije.

Općenito, svaka metoda proširenja koju definiramo u Kotlinu dostupna nam je za upotrebu u Javi. Trebali bismo se sjetiti da infiks metodu još treba nazvati točkom i zagradama. Isto je s ekstenzijama operatora - ne možemo koristiti samo znak plus (+). Ovi su sadržaji dostupni samo u Kotlin.

Međutim, neke standardne metode biblioteke Kotlin u Javi ne možemo nazvati, na primjer neka ili primijeniti, jer su označeni s @InlineOnly.

4.1. Vidljivost funkcije prilagođenog proširenja u Javi

Upotrijebimo jednu od prethodno definiranih funkcija proširenja - String.escapeXml (). Pozvana je naša datoteka koja sadrži metodu ekstenzije StringUtil.kt.

Sada, kada trebamo nazvati metodu proširenja s Jave, moramo koristiti naziv klase StringUtilKt. Imajte na umu da moramo dodati Kt sufiks:

Niz xml = "bok"; String escapedXml = StringUtilKt.escapeForXml (xml); assertEquals ("hi", escapedXml);

Molimo obratite pažnju na prvu escapeForXml parametar. Ovaj dodatni argument je tip prijemnika funkcije proširenja. Kotlin s funkcijom produženja najviše razine je čist Java razred sa statičkom metodom. Zato treba nekako prenijeti original Niz.

I naravno, baš kao i u Java, možemo koristiti statički uvoz:

uvoz statičke com.baeldung.kotlin.StringUtilKt. *;

4.2. Pozivanje ugrađene metode produženja Kotlina

Kotlin pomaže nam u pisanju koda lakše i brže pružajući mnoge ugrađene funkcije proširenja. Na primjer, postoji Niz.pisati velikim slovom () metoda, koja se može pozvati izravno iz Java:

Naziv niza = "john"; Niz capitalizedName = StringsKt.capitalize (ime); assertEquals ("Ivan", veliko ime);

Međutim, ne možemo nazvati metode produženja označene s @InlineOnly iz Java, na primjer:

inline zabava T.let (blok: (T) -> R): R

4.3. Preimenovanje generirane Java statičke klase

Već znamo da a Kotlin funkcija produženja je statična Java metoda. Preimenujmo generirano Java razred s bilješkom @file: JvmName (name: String).

To treba dodati na vrh datoteke:

@file: JvmName ("Strings") paket com.baeldung.kotlin fun String.escapeForXml (): String {return this .replace ("&", "&") .replace ("<", "", ">" )}

Sada, kada želimo nazvati metodu proširenja, jednostavno moramo dodati Žice naziv klase:

Strings.escapeForXml (xml);

Također, još uvijek možemo dodati statički uvoz:

uvoz statičkih com.baeldung.kotlin.Strings. *;

5. Sažetak

Metode proširenja korisni su alati za proširivanje vrsta koje već postoje u sustavu - ili zato što nemaju potrebnu funkcionalnost ili jednostavno za olakšavanje upravljanja nekim određenim područjem koda.

Ovdje smo vidjeli neke metode produženja koje su spremne za upotrebu u sustavu. Pored toga, istražili smo razne mogućnosti produžnih metoda. Neke primjere ove funkcije možete pronaći na GitHubu.