A Kotlin az új Java

Ha már Java fejlesztőként dolgozol egy ideje, talán már elgondolkoztál azon, hogy melyik legyen a következő nyelv, amibe beleásod magad. Érdemes ránézni például a Clojure, a Rust vagy a Haskell izgalmas megoldásaira, de ha olyan nyelvvel szeretnél foglalkozni, amivel pénzt is lehet keresni és emellett kellemes vele kódot írni, akkor válasszd a Kotlint.

Szóval mi is a Kotlin?

  • A JetBrains saját fejlesztésű programozási nyelve, azé a cégé, akik az IDEA fejlesztői környezet mögött is állnak.
  • Egy egyszerű, és sokoldalú Java alternatíva
  • Ami kifogástalan együttműködésre képes a Java-val
  • Java bájtkódra fordul
  • A JVM-en fut
  • Továbbá képes Javascript-re is fordulni

Ha elolvassuk a dokumentációt, akkor találhatunk még pár ígéretes dolgot:

  • Többet elérhetünk kevesebb kód írásával
  • Megoldást kínál sok, Java-ban fellelhető problémára
  • Továbbra is használhatjuk a Java ökoszisztémát vele
  • Frontend és backend kódot is tudunk írni ugyanazon a nyelven
  • 100%-ban együttműködő a Java-val
  • E tekintetben jobban teljesít, mint más alternatívák (Clojure, Scala)
  • És csak egy vékony réteg komplexitást ad hozzá a Java-hoz

Jól hangzik, nem? Mielőtt rátenyerelünk a Letöltés gombra azért még tekintsük át, hogy mit is jelent ez a gyakorlatban.

Érték- és adatosztályok

Amit itt láthatunk, az egy jó öreg POJO a szokásos boilerplate kóddal:

Az értékosztályok készítése elég nehézkes még akkor is, ha Lombok-ot használunk (a Lombok használatához telepíteni kell egy beépülő modult a fejlesztői környezetünkbe, ami nem minden esetben megoldható). Habár ehhez segítséget nyújt az IDEA (illetve az Eclipse), különböző kódgeneráló eszközökkel, ezek nem igazán megbízhatóak (gondoljunk csak arra, amikor hozzáadunk egy új mezőt az osztályhoz és elfelejtjük újragenerálni az equals metódust.

Nézzük meg, hogy néz ki ugyanez Kotlin-ban:

Hoppá! Ehhez lényegesen kevesebbet kellett gépelni a Java-verzióhoz képest! A Kotlin adatosztályok a következőket adják:

  • equals + hashCode,
  • toString és
  • getterek + setterek Ezeken kívül megkapjuk a copy metódust, amivel másolatokat tudunk készíteni már meglévő adatosztály példányokról. Erről itt lehet többet olvasni.

String interpoláció

A String-ek manipulálása Java-ban nem éppen kényelmes művelet. Ezen segíthet a String.format, de nem túl sokat.

A Kotlin ennek a problémának a megoldására a String interpolációt nyújtja, amivel kényelmesebben tudunk kezelni szövegeket:

Kiegészítő funkciók

Dekorátorokat írni Java-ban trükkös feladat és nem mindig sikerül tökéletesen. Például, ha egy olyan dekorátort szeretnénk készíteni, ami a List interfész összes implementációjával képes működni, akkor nem szerencsés a List-et kiterjesztenünk, mert úgy elég sok metódust kellene implementálnunk, ehelyett érdemesebb az AbstractList-ből kiindulnunk:

Ha viszont valami olyasmit akarunk dekorálni, ami nem ad az AbstractList-hez hasonló könnyítéseket, vagy akár az általunk dekorálandó osztály final, akkor gondban vagyunk. Ebben a problémában tudnak segítséget nyújtani a kiegészítő funkciók:

Ez a funkció dekorátorként viselkedik minden List példányon. A Java-s alternatívával összehasonlítva ez az egy soros lényegesen egyszerűbb és képes final osztályokon is működni. Természetesen ez sem mindenre megoldás.

Null biztonság

A null-ok ellenőrzése általában sok logikai művelettel és boilerplate-tel jár. A Java 8 megjelenése óta ezen már tudunk segíteni az Optional használatával, de mi történik akkor, ha egy Optional referencia a null? Bizony, ilyenkor megkapjuk a szokásos NullPointerException-t, ami a Java 20 éves fennállása óta még mindig nem képes megmondani, hogy mi volt a null. Nézzük meg a következő példát:

A Kotlin használatával több opciónk is van. Ha együtt akarunk működni Java-projektekkel, vagy egy már meglévő Java-projekten használunk Kotlin-t is, akkor lehet a null biztonsági operátort (?) használni:

A ? jobb oldalán lévő kód csak akkor fog futni, ha a bal oldalán lévő kifejezés nem null. A let funkció létrehoz egy lokális scope-ot azzal az objektummal, amin meg lett hívva, így itt az it változó az it.city-re fog mutatni a visszatéréskor.

Ha viszont nem kell Java-kóddal együttműködni, akkor jobban járunk, ha egyáltalán nem használunk null-t a projektünkön:

Ha nincs a kódbázisunkban null (nics ? sehol), akkor lényegesen egyszerűbb lesz az egész.

Típus kikövetkeztetés

A Kotlin támogatja a típusok kikövetkeztetését, ami azt jelenti, hogy sok esetben a kontextusból ki tudja deríteni a fordító a típusok megjelölése nélkül is azt, hogy egy-egy referencia milyen típussal rendelkezik. Ez kicsit olyan, mint a gyémántjelölés Java-ban, csak sokkal sokoldalúbb! Nézzük meg a következő példát:

Ez Kotlin-ban alapból hasonlóan néz ki:

Amíg rá nem hagyjuk a Kotlin-fordítóra, hogy kikövetkeztesse a változóink típusait:

Vagy akár a funkciók visszatérési értékeit:

Nincsenek ellenőrzött kivételek

Az alábbi kódot valószínűleg már milliószor láthattad:

Régimódi Java IO. Ugyanez Kotlin-ban így néz ki:

Itt több dolog is történik egyszerre. Először is a Kotlin-ban nincsenek ellenőrzött kivételek, így itt az IO végrehajtása során nem kell elkapnunk az esetlegesen keletkező kivételeket. Másodszor a Kotlin az összes Closeable osztályhoz hozzáadja az use műveletet, ami a dokumentáció szerint az alábbiakat végzi el:

Executes the given [block] function on this resource and then closes it down correctly whether an exception is thrown or not. (Kivonat a Kotlin dokumentációból)

Ezeken kívül a File osztályhoz hozzáadott readLines funkciót is láthatjuk működés közben. Ez a minta a Kotlin által adott függvény-könytárban sokszor előfordul. Ha használtál már Guava-t vagy esetleg Apache Commons-t, akkor az azokban található függvények sokszor visszaköszönnek mint Kotlin kiegészítő funkciók hozzáadva a JDK osztályokhoz. Ezeket használva sok kellemetlenségtől megkímélhetjük magunkat.

Lambda támogatás

Nézzünk meg egy példát egy Java-s lambdára:

Mivel a Java-ban nincsen külön szintaxis, amivel metódusok szignatúráját írhatnánk le, általában egy interfészt kell létrehozni nekik. Az alábbi példában ugyan használhatnánk a Function<String, Boolean> típust, de ez csak olyan függvényekre működik, amiknek egy paraméterük van. Erre vannak részmegoldások a JDK-ban, de ha valaki ránéz a kódunkra, lehet, hogy nem lesz egyértelmű számára, hogy mire is való egy BiFunction. Ezen egy kicsit javít a Kotlin:

A Kotlin szintaxist ad funkciók leírására az alábbi módon: (ParamType1, ...ParamTypeN) -> ReturnType. Mivel a Kotlin-ban vannak függvény- és mező referenciák is, ezért lehet hivatkozni egy már létező objektum egy függvényére is! Az alábbi példában egy konkrét példány filterBy műveletére hivatkozunk így:

Funkcionális programozás

Mostanában sokat hallani a funkcionális programozásról és a Java 8 megjelenésével már használhatjuk az Oracle által megálmodott eszköztárat, a Stream API-tis erre a célra, ami így működik:

Ennek a megfelelője a Kotlinba nagyon hasonló, de némileg mégis más:

A lényeges különbség az, hogy nincs explicit konverzió stream-ekre, mivel az összes Kotlin collection támogatja őket alapból. Ennek egyenes következménye az is, hogy a fenti példában nem kell lambda-t átadnunk a flatMap függvénynek. Az eredmények összegyűjtése is automatikus (nincs szükség a Collectors.to* metódusok használatára). Ebben a példában csak azért kellett a toSet függvényt használnunk, mert Set-et akarunk visszaadni. Ha ez nem lenne elvárás, akkor elhagyhatnánk a .toSet() hívást.

Együttműködés Kotlin és Java között

Ha az együttműködés a két nyelv között nem kielégítő az sokakat elrettenthet (és el is rettent más nyelvekben), de a JetBrains itt kiköszörülte a csorbát:

Az együttműködés akadály- és fájdalommentes a két kódbázis között. Java- és Kotlin-osztályok projekten belül is vegyíthetők és a Kotlin ad pár annotációt (például a @JvmStatic a fenti példában), amivel a Kotlin osztályokat lehet felokosítani úgy, hogy Java oldalról könnyű legyen a használatuk. Erről itt lehet többet olvasni.

Ha megnézzük a fenti példákat, akkor jól láthatóvá válik egy séma: a Kotlin megőrzi a Java jó ötleteit, azokat feljavítja, míg a hibáit próbálja kiküszöbölni. Az, hogy a Google az Android egyik hivatalos nyelvévé tette a Kotlin-t szintén ezt támasztja alá.

Mit mondjak a főnökömnek?

Ha esetleg meggyőztek a fentiek és kipróbálnád a Kotlin-t a munkahelyeden, de nincs ötleted, hogy mit mondj a főnöködnek és a csapattársaidnak, akkor adok pár tippet, amik talán segítenek majd:

  • A Kotlin az iparból érkezett, nem egy egyetem falai közül. Valós problémákat old meg, amikkel programozók nap mint nap találkoznak
  • Ingyenes és nyílt forráskódú
  • Van hozzá egy könnyen használható Java -> Kotlin konvertáló eszköz
  • Gyakorlatilag 0 energiabefektetéssel keverhető a Java- és a Kotlin-kód
  • Minden már létező Java-eszközt és keretrendszert lehet használni Kotlin-ból is
  • A Kotlin-hoz a piac legjobb integrált fejlesztői környezete ad támogatást (aminek van ingyenes verziója)
  • Könnyen olvasható, még a nem-Kotlin fejlesztők is át tudják nézni a kódodat
  • Nem kell elköteleződni a Kotlin mellett a projekteden: elég az is, ha csak a teszteket írod az elején Kotlin-ban
  • A JetBrains nem valószínű, hogy abbahagyja a nyelv fejlesztését egyhamar, mivel bevallottan is az a céljuk, hogy a bevételeiket növeljék vele
  • A Kotlin közösség meglehetősen aktív és a KEEP-en akár te is tehetsz javaslatokat a nyelv fejlesztési irányát illetően

A kérdést, hogy több-e a Kotlin, mint egy egyszeri hype, viszont csak Te tudod eldönteni. Ha ki akarod próbálni a nyelvet, akkor itt van pár tipp, hogy hol kezdd: