Bevezetés a Kotlin nyelvbe

1. Áttekintés

Ebben az oktatóanyagban megnézzük a Kotlin-t, egy új nyelvet a JVM világában, és néhány alapvető jellemzőjét, beleértve az osztályokat, az öröklődést, a feltételes utasításokat és a ciklusos konstrukciókat.

Ezután megvizsgáljuk azokat a főbb jellemzőket, amelyek vonzóvá teszik a Kotlint, beleértve a null biztonságot, az adatosztályokat, a kiterjesztési funkciókat Húr sablonok.

2. Maven-függőségek

A Kotlin használatához a Maven projektben hozzá kell adnia a Kotlin szabványos könyvtárat a könyvtárához pom.xml:

 org.jetbrains.kotlin kotlin-stdlib 1.0.4 

A JUnit támogatásának hozzáadásához a Kotlinhoz a következő függőségeket is fel kell vennie:

 org.jetbrains.kotlin kotlin-test-junit 1.0.4 teszt junit junit 4.12 teszt 

A kotlin-stdlib, a kotlin-test-junit és a junit legújabb verzióit megtalálhatja a Maven Central oldalon.

Végül konfigurálnia kell a forráskönyvtárakat és a Kotlin plugint a Maven-összeállítás végrehajtásához:

 $ {project.basedir} / src / main / kotlin $ {project.basedir} / src / test / kotlin kotlin-maven-plugin org.jetbrains.kotlin 1.0.4 fordítás 

A kotlin-maven-plugin legújabb verzióját a Maven Central-ban találja.

3. Alapszintaktika

Nézzük meg a Kotlin nyelv alapvető építőköveit.

Van némi hasonlóság a Java-val (pl. A csomagok meghatározása ugyanúgy történik). Vessünk egy pillantást a különbségekre.

3.1. Funkciók meghatározása

Határozzunk meg egy olyan függvényt, amelynek két Int paramétere van Int visszatérési típus:

szórakoztató összeg (a: Int, b: Int): Int {return a + b}

3.2. Helyi változók meghatározása

Hozzárendelés egyszeri (csak olvasható) helyi változó:

val a: Int = 1 val b = 1 val c: Int c = 1

Vegye figyelembe a változó típusát b egy Kotlin-fordító következtet. Meghatározhatnánk változó változókat is:

var x = 5 x + = 1

4. Választható mezők

Kotlin alapvető szintaxissal rendelkezik egy olyan mező meghatározásához, amely érvényteleníthető (opcionális). Ha azt akarjuk nyilvánítani, hogy az adott típusú mező érvénytelen, akkor kérdőjellel ellátott utótípust kell használnunk:

val email: Karakterlánc?

Amikor megsemmisítendő mezőt definiált, tökéletesen érvényes a nulla hozzá:

val email: Karakterlánc? = null

Ez azt jelenti, hogy egy e-mail mezőben lehet a nulla. Ha megírjuk:

val email: String = "value"

Ezután értéket kell rendelnünk az e-mail mezőhöz ugyanabban az utasításban, amelyet deklarálunk e-mailként. Nem lehet nullértékű. Visszajövünk Kotlinba nulla egy későbbi szakaszban.

5. Osztályok

Bemutatjuk, hogyan lehet létrehozni egy egyszerű osztályt egy adott termékkategória kezeléséhez. A mi ItemManager Az alábbi osztály rendelkezik egy alapértelmezett konstruktorral, amely két mezőt tölt be - categoryId és dbConnection - és választható email terület:

class ItemManager (val categoryId: String, val dbConnection: String) {var email = "" // ...}

Hogy ItemManager (…) A construct konstruktort és két mezőt hoz létre az osztályunkban: categoryId és dbConnection

Vegye figyelembe, hogy konstruktorunk a val kulcsszó az érveihez - ez azt jelenti, hogy a megfelelő mezők lesznek végső és változhatatlan. Ha használtuk volna a var kulcsszó (ahogy a email mező), akkor ezek a mezők változtathatóak lennének.

Hozzunk létre egy példányt az ItemManager-ről az alapértelmezett konstruktor segítségével:

ItemManager ("cat_id", "db: // kapcsolat")

Építhetnénk ItemManager megnevezett paraméterek felhasználásával. Nagyon hasznos, ha van olyan, mint ebben a példában a függvény, amely két azonos típusú típust vesz fel, pl. Húr, és nem akarja összetéveszteni sorrendjüket. Az elnevezési paraméterek segítségével kifejezetten megírhatja, hogy melyik paraméter van hozzárendelve. Osztályban ItemManager két mező van, categoryId és dbConnection így mindkettőre meg lehet hivatkozni megnevezett paraméterekkel:

ItemManager (categoryId = "catId", dbConnection = "db: // Connection")

Nagyon hasznos, ha több argumentumot kell átadnunk egy függvénynek.

Ha további kivitelezőkre van szüksége, akkor azokat a konstruktőr kulcsszó. Határozzunk meg egy másik konstruktort, amely szintén beállítja a email terület:

konstruktor (categoryId: Karakterlánc, dbConnection: Karakterlánc, e-mail: String): ez (categoryId, dbConnection) {this.email = email}

Ne feledje, hogy ez a konstruktor meghívja az alapértelmezett konstruktort, amelyet a fentiekben definiáltunk az e-mail mező beállítása előtt. És mivel már meghatároztuk categoryId és dbConnection hogy megváltoztathatatlan a val kulcsszó az alapértelmezett konstruktorban, nem kell megismételnünk a val kulcsszó a további konstruktorban.

Most hozzunk létre egy példányt a további konstruktor használatával:

ItemManager ("cat_id", "db: // kapcsolat", "[email protected]")

Ha egy példány metódust szeretne megadni a ItemManager, ezt a szórakozás kulcsszó:

fun isFromSpecificCategory (catId: String): Logikai {return categoryId == catId}

6. Öröklés

Alapértelmezés szerint Kotlin osztályai a kiterjesztés miatt zárva vannak - a megjelölt osztály megfelelője végső Java-ban.

Annak megadásához, hogy egy osztály nyitva van-e a kiterjesztéshez, használja a nyisd ki kulcsszó az osztály meghatározásakor.

Határozzunk meg egy Tétel a bővítésre nyitva tartó osztály:

open class Item (val id: String, val name: String = "unknown_name") {open fun getIdOfItem (): String {return id}}

Ne feledje, hogy a getIdOfItem () módszer nyitottként. Ez lehetővé teszi annak felülírását.

Most hosszabbítsuk meg a Tétel osztály és felülírja a getIdOfItem () módszer:

class ItemWithCategory (id: String, name: String, val categoryId: String): Item (id, name) {felülírja a fun getIdOfItem (): String {return id + name}}

7. Feltételes nyilatkozatok

Kotlinban feltételes nyilatkozat ha egyenértékű egy olyan funkcióval, amely valamilyen értéket ad vissza. Nézzünk meg egy példát:

fun makeAnalyisOfCategory (catId: String): Unit {val result = if (catId == "100") "Yes" else "No" println (result)}

Ebben a példában azt látjuk, hogy ha catId egyenlő a „100” feltételes mondattal „Igen” -vel tér vissza, különben „Nem” -re tér vissza. A visszaküldött érték hozzárendelésre kerül eredmény.

Létrehozhat egy normálisat hamás Blokk:

val szám = 2 if (10. szám) {println ("a szám nagyobb, mint 10")}

Kotlin is nagyon hasznos mikor parancs, amely úgy működik, mint egy speciális kapcsoló utasítás:

val name = "John" mikor (név) {"John" -> println ("Hi man") "Alice" -> println ("Hi lady")} 

8. Gyűjtemények

Kétféle gyűjtemény létezik Kotlinban: változtatható és megváltoztathatatlan. Amikor megváltoztathatatlan gyűjteményt hozunk létre, az csak olvasható:

val elemek = listOf (1, 2, 3, 4)

A listán nincs hozzáadandó függvény elem.

Ha módosítható listát akarunk létrehozni, akkor ezt használnunk kell mutableListOf () módszer:

val rwList = mutableListOf (1, 2, 3) rwList.add (5)

Egy módosítható listának van add () metódust, hogy hozzáfűzhessünk egy elemet hozzá. Más típusú gyűjteményekkel is egyenértékű módszer létezik: mutableMapOf (), mapOf (), setOf (), mutableSetOf ()

9. Kivételek

A kivételkezelés mechanizmusa nagyon hasonló a Java-hoz.

Minden kivétel osztály kiterjed Dobható. A kivételnek tartalmaznia kell üzenetet, veremkövetést és opcionális okot. Minden kivétel Kotlinban nincs ellenőrizve, vagyis a fordító nem kényszerít bennünket, hogy elkapjuk őket.

Egy kivétel objektum dobásához a dob kifejezést kell használnunk:

dobási kivétel ("msg")

A kivétel kezelése a használatával történik próbáld meg ... elkapni a blokkot (végül választható):

próbáld meg {} catch (e: SomeException) {} végül {}

10. Lambdas

Kotlinban definiálhatnánk a lambda függvényeket, és argumentumként átadhatnánk más függvényeknek.

Nézzük meg, hogyan definiálható egy egyszerű lambda:

val sumLambda = {a: Int, b: Int -> a + b}

Meghatároztuk sumLambda függvény, amely két típusú argumentumot vesz fel Int érvként és visszatér Int.

Áthaladhatunk egy lambdán:

@Test fun givenListOfNumber_whenDoingOperationsUsingLambda_shouldReturnProperResult () {// megadott val listOfNumbers = listOf (1, 2, 3) // amikor val sum = listOfNumbers.reduce {a, b -> a + b} // majd assertEquals (6, összeg)}

11. Hurkos konstrukciók

Kotlinban a gyűjtemények átlapolása egy szabvány használatával történhet be konstrukció:

val számok = arrayOf ("első", "második", "harmadik", "negyedik")
for (n számokban) {println (n)}

Ha egész számtartományon belül akarunk iterálni, használhatunk egy tartománykonstrukciót:

for (i 2..9 2. lépésben) {println (i)}

Vegye figyelembe, hogy a fenti példában szereplő tartomány mindkét oldalon átfogó. A lépés A paraméter nem kötelező, és egyenértékű azzal, hogy minden egyes iterációban kétszer növeljük a számlálót. A kimenet a következő lesz:

2 4 6 8

Használhatnánk a rangeTo () be van kapcsolva Int osztály a következő módon:

1.rangeTo (10) .térkép {it * 2}

Az eredmény tartalmazni fogja (vegye figyelembe, hogy rangeTo () is befogadó):

[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]

12. Semmi biztonság

Nézzük meg a Kotlin egyik legfontosabb jellemzőjét - a biztonságot, amely beépül a nyelvbe. Annak szemléltetésére, hogy ez miért hasznos, létrehozunk egy egyszerű szolgáltatást, amely visszaadja az Tétel tárgy:

class ItemService {fun findItemNameForId (id: String): Elem? {val itemId = UUID.randomUUID (). toString () return Item (itemId, "név- $ itemId"); }}

A legfontosabb dolog, amit észre kell venni, a módszer visszatérő típusa. Ez egy tárgy, amelyet a kérdőjel követ. Ez egy kotlin nyelvű konstrukció, ami azt jelenti Tétel a módszerből visszaküldött érték semmis lehet. Ezt az esetet fordításkor kell kezelnünk, el kell döntenünk, hogy mit akarunk kezdeni az adott objektummal (többé-kevésbé egyenértékű a Java 8-zal) Választható típus).

Ha a metódus aláírásának kérdőjel nélküli típusa van:

fun findItemNameForId (id: String): Elem

akkor a hívó kódnak nem kell null esetet kezelnie, mert a fordító és a Kotlin nyelv garantálja, hogy a visszaküldött objektum nem lehet null.

Másképp, ha van egy nullázható objektum, amelyet egy metódusnak adnak át, és az esetet nem kezelik, akkor az nem fordítódik le.

Írjunk egy tesztesetet a Kotlin-típusbiztonságról:

val id = "item_id" val itemService = ItemService () val result = itemService.findItemNameForId (id) assertNotNull (eredmény? .let {it -> it.id}) assertNotNull (eredmény !!. id) 

Látjuk itt, hogy a módszer végrehajtása után findItemNameForId (), a visszaküldött típus Kotlin Nullable. Az objektum mezőjének elérése (id), azt az esetet fordításkor kell kezelnünk. Módszer let () csak akkor hajt végre, ha az eredmény nem nullázható. énd mező elérhető a lambda függvény belsejében, mert az semmiképp sem biztonságos.

Az érvénytelen objektum mező elérésének másik módja a Kotlin operátor használata !!. Ez egyenértékű:

if (eredmény == null) {dobásNpe (); } visszatérési eredmény;

Kotlin ellenőrzi, hogy az adott objektum a nulla ha igen, akkor dob egy NullPointerException, különben megfelelő tárgyat ad vissza. Funkció dobásNpe () egy Kotlin belső funkció.

13. Adatosztályok

Nagyon jó nyelvi konstrukció, amely Kotlinban megtalálható, az adatosztályok (ez egyenértékű a Scala nyelvű „case class” -val). Az ilyen osztályok célja csak adatok tárolása. Példánkban volt egy Tétel osztály, amely csak az adatokat tárolja:

adatosztály Tétel (val id: String, val név: String)

A fordító módszereket fog létrehozni számunkra hash kód(), egyenlő (), és toString (). Jó gyakorlat az adatosztályok megváltoztathatatlanná tétele az a használatával val kulcsszó. Az adatosztályok alapértelmezett mezőértékekkel rendelkezhetnek:

adatosztály Elem (val id: String, val name: String = "unknown_name")

Ezt látjuk név mező alapértelmezett értéke „ismeretlen_név”.

14. Bővítési funkciók

Tegyük fel, hogy van olyan osztályunk, amely a harmadik fél könyvtárának része, de egy további módszerrel szeretnénk bővíteni. Kotlin ezt lehetővé teszi számunkra a kiterjesztési függvények használatával.

Vegyünk egy példát, amelyben van egy elemlistánk, és véletlenszerű elemet akarunk venni abból a listából. Új funkciót szeretnénk hozzáadni véletlen() harmadik félnek Lista osztály.

Így néz ki Kotlinban:

szórakozás List.random (): T? {if (this.isEmpty ()) null return get (ThreadLocalRandom.current (). nextInt (count ()))}}

A legfontosabb, amit itt észre kell venni, a módszer aláírása. A metódus előtagja annak az osztálynak a neve, amelyhez hozzáadjuk ezt az extra metódust.

A kiterjesztési módszeren belül egy lista hatókörét használjuk, ezért a ez hozzáférést adott a listapéldány-módszerekhez, mint például üres() vagy számol(). Akkor képesek vagyunk felhívni véletlen() módszer bármely listán, amely az adott hatókörbe tartozik:

fun getRandomElementOfList (lista: Lista): T? {return list.random ()}

Létrehoztunk egy módszert, amely listát készít, majd végrehajtja az egyéni kiterjesztés funkciót véletlen() hogy korábban meghatározták. Írjunk tesztesetet új funkciónkra:

val elemek = listOf ("a", "b", "c") val result = ListExtension (). getRandomElementOfList (elements) assertTrue (elements.contains (result)) 

A harmadik fél osztályait „kibővítő” függvények meghatározásának lehetősége nagyon hatékony szolgáltatás, és tömörebbé és olvashatóbbá teheti kódunkat.

15. Vonósablonok

A Kotlin nyelv nagyon szép tulajdonsága a sablonok használata Húrs. Nagyon hasznos, mert nincs szükségünk összefűzésre Húrs manuálisan:

val firstName = "Tom" val secondName = "Mary" val concatOfNames = "$ firstName + $ secondName" val sum = "négy: $ {2 + 2}" 

Kiértékelhetünk egy kifejezést is a ${} Blokk:

val itemManager = ItemManager ("cat_id", "db: // kapcsolat") val result = "függvény eredménye: $ {itemManager.isFromSpecificCategory (" 1 ")}"

16. Kotlin / Java interoperabilitás

Kotlin - A Java interoperabilitása zökkenőmentesen egyszerű. Tegyük fel, hogy van egy Java osztályunk, amelynek módszere működik Húr:

class StringUtils {public static String toUpperCase (String name) {return name.toUpperCase (); }}

Most azt a kódot akarjuk végrehajtani a Kotlin osztályunkból. Csak azt az osztályt kell importálnunk, és problémamentesen futtathatnánk a java metódust Kotlinból:

val name = "tom" val res = StringUtils.toUpperCase (név) assertEquals (res, "TOM")

Mint látjuk, a java metódust használtuk a Kotlin kódból.

A Kotlin kód meghívása Java-ból szintén nagyon egyszerű. Határozzuk meg az egyszerű Kotlin-függvényt:

osztály MathematicsOperations {fun addTwoNumbers (a: Int, b: Int): Int {return a + b}}

Végrehajtó addTwoNumbers () Java kódból nagyon egyszerű:

int res = új MathematicsOperations (). addTwoNumbers (2, 4); assertEquals (6, res);

Úgy látjuk, hogy a Kotlin-kód hívása átlátható volt számunkra.

Amikor meghatározunk egy metódust a java-ban, akkor a visszatérési típus a üres, Kotlinban a visszatérő érték a Mértékegység típus.

Van néhány speciális azonosító a Java nyelven ( van, tárgy, ban ben, ..) hogy a Kotlin-kódban való használatuk elől meg kell kerülni. Például meghatározhatunk egy nevet tartalmazó metódust tárgy() de emlékeznünk kell arra, hogy elkerüljük ezt a nevet, mivel ez egy speciális azonosító a java-ban:

fun `object` (): String {adja vissza" ez az objektum "}

Akkor végre tudjuk hajtani ezt a módszert:

`tárgy` ()

17. Következtetés

Ez a cikk bemutatja a Kotlin nyelvét és annak főbb jellemzőit. Az egyszerű fogalmak bevezetésével kezdődik, mint például a ciklusok, a feltételes utasítások és az osztályok meghatározása. Ezután bemutat néhány fejlettebb funkciót, például a kiterjesztési funkciókat és a null biztonságot.

Mindezen példák és kódrészletek megvalósítása megtalálható a GitHub projektben.