Kuolema nullpointerexceptioneille: Kotlin ftw!

Lomaillessa ja sairastaessa on hyvin aikaa leikkiä jollain jolle ei ole ollut kysyntää ns oikeissa, hiellä ja tuskalla väännetyissä Wakavissa Projekteissa. Tällä kertaa tutkaan osui Kotlin, johon on ollut tarkoitus perehtyä tilaisuuden tullen.

Kotlin on tuorein lisäys JVM-perheen kieliin; Eli kuten Scala, Clojure, ja Groovy, se on ihan oma erillinen kielensä, syntaksinsa, ja filosofiansa, mutta kun se menee kääntäjän läpi, putkesta ulos tulee Java-virtuaalikoneen bytecodea – vaatii tosin minimitasoksi Java 6 myllyn.

Ajonaikaiset virheet ohjelmissa ovat nykypäivän ohjelmistokehityksessä niitä kalleimpia virheitä – koska ne löytyvät vain kattavalla testauksella, voivat vaatia hyvinkin eksoottisia tiloja ja kombinaatioita ilmentyäkseen, ja mitä myöhemmin ne löytyvät, sitä enemmän ne maksavat. Esim. käyttöönottovaiheen jälkeen löytyvä bugi pitää ensin havaita, sitten raportoida, sitten toistaa, sitten ymmärtää, sitten korjata, sitten testata korjaus, ja testata ettei korjaus rikkonut mitään muualla, jne. Tästä kertyy ihan kohtuullisesti hintaa pienille asioille. Java-kielessä on alusta alkaen ilmennyt kahta eri virhettä yli kaiken muun: ClassCastException, sekä NullPointerException. Java 5 onnistui aikanaan hävittämään edellisen lähes sukupuuttoon Generics tyypitettyjen kokoelmien myötä. Mutta NullPointer on edelleen valitettavan yleinen virhe. Ja kun se paukahtaa, se usein valuu pinossa ylöspäin, ja voi ilmentyä hyvin mielikuvituksellisin tavoin – tai voi aiheuttaa seurauksia jotka näkyvät jossain aivan muualla myöhemmin. Eli pirullisia virheitä.

Nullpointereita on jahdattu eri tavoin. Olen itse opettanut ja kirjoitellut siitä miten Java-kielellä koodatessa voi tiedostaa tämän, ja koodata fiksusti. NullPointer paholainen iskee tyypillisemmin kun metodi palauttaa kokoelman sijasta null-arvon. Eli parempi filosofia on palauttaa aina ei-null arvo, esim. tyhjä. Jos jossain oikeasti tulee vastaan niin harvinainen tapaus, että null ja tyhjä ovat eri asia ja molemmat tarpeen palauttaa, niin se poikkeus on hyvä dokumentoida ja nimetä selkeästi, jotta kutsuja osaa käsitellä arvot oikein. Scala ja Groovy hoitavat nulleja omilla tavoillaan, mutta molemmat kielet edelleen sallivat null arvoja. Java 8 esitteli uuden Optional-tyypin, josta olen myös kirjaillut, ja se tuo vähän helpotusta ongelmiin oikein käytettynä – mutta ei sekään ongelmaa poista, ja mikään ei sitä pakota käyttämään.

Joten – long story short – Kotlin kielen mainostetuin uutuuspiirre on juurikin kuolema nullpointtereille, taas uudella ja tuoreella näkökulmalla. Mutta ei mennä asioiden edelle. Kotlin on syntaksiltaan ja toiminnaltaan eniten lähellä Scala-kieltä, ja Java-koodaajillekin tuttu.

fun main(args: Array<String>) {
  print("Kuolema NULLPOINTEREILLE!")
}

Jeah, puolipisteet valinnaisia, pääohjelman voi tehdä ilman luokkaa. Itse asiassa on myös mahdollista tehdä Kotlin scriptitiedosto, joka sisältää vain pääohjelman koodin:

print("Kuolema NULLPOINTEREILLE scriptissä!")

Kotlin käännetään kotlinc-kääntäjällä, joka voi suoraan paketoida java-kirjastot mukaan. Lopputuotos voi olla .class tiedostoja, tai suoraan ajettava .jar. Kotlin voi vapaasti importoida ja kutsua Java-kirjastoja, sekä JVM sisältä että mitä hyvänsä lisäkirjastoa mitä on tehty sitten vuoden 1995.

kotlinc app.kt -include-runtime -d app.jar

Miten Kotlin sitten auttaa nullpointerien kanssa? Kotlin ei salli normaalien tyyppien asettamista null-arvoon: kääntäjä estää sen. Esim. tyyppi String vaatii aina ei-null arvon. Jos haluat asettaa null-arvon, tyypin perään tulee kysymysmerkki merkiksi, esim. String?

var name:String?
var email:String
name = null
email = null // This line does not compile at all!
print("HELLO " + name + "!")
print("Your email is " + email)

Ylläolevassa koodiesimerkissä näet molemmat käytössä. Jos halutaan siis varata oikeus käyttää null-arvoja, se pitää näkyä jo alunperin tyyppimäärityksessä. On siis varsin mahdollista käyttää null-arvoja – mutta useimmiten ne ovat vain puhdasta laiskuutta. Useimmiten kun on mielijohde palauttaa null-arvo, onkin fiksumpaa palauttaa ns tyhjä arvo, esim. tyhjä String, tyhjä List, jne, tai heittää poikkeus. Niihin harvoihin tapauksiin kun null arvo on oikeasti kätevä, se on helppo ottaa käyttöön.

Mitä muuta jännää on Kotlinissa, verrattuna Java/Scala kieliin esim? Aika paljolti paletti molempien parhaita puolia. Primitiivityypit on poistettu: Kaikki ovat oliotyyppejä. Ei ns checked exceptions poikkeuksia, kaikki ovat nykymuodin mukaan runtime exception tyyppiä, eli käsitellään kun halutaan, ei ole pakko. Nykymuodin mukaan myös kielessä on paljon älykkyyttä ja päättelyä: esim. muuttuja/vakiotyyppiä ei tarvitse määrittää jos kääntäjä sen jo osaa päätellä arvon perusteella. Erikseen löytyy val ja var avainsanat immutable/mutable käyttöä varten. Tottakai lambda expressionit pelaavat mainiosti.

Kielestä on sitten vastaavasti jätetty pois monia piirteitä, joilla Java/Scala koodaajat ampuvat itseään lahjakkaasti jalkaan, esim. static avainsanat ja osat, implicit conversions, ja rohkaisu on ratkoa ongelmia siten että koodi pysyy luettavana ja selkeänä. Toisin kuin Scala, kieli on myös rakennettu modernin Java 8 pohjalle, eli on lähempänä nykysyntaksia mm. Lambdojen ja Stream käsittelyn osalta. Itse pidän myös esim. funktioparametrien oletusarvoista, ja mahdollisuudesta asettaa parametreille arvot nimen perusteella. Tämä vähentää tarpeetonta polymorfismia – toki kohtuudella käytettynä tämäkin, muuten polymorfisuus korvautuu modaalisuudella joka taas ei ole hyvä vaihtokauppa.

2016-06-10 13.13.59

Firman Flamingo hyväksyy Kotlinin

Kotlin on tosiaan melko tuore tulokas kentällä: JetBrains niminen paja lanseerasi sen vuonna 2011, vuonna 2012 se vapautettiin Apache lisenssillä open sourceksi, ja nyt vuonna 2016 siitä on julkaistu vakaaksi laskettava versio 1.0, vuoden alusta. Sen osuus on sen verran marginaalinen ettei vielä näy esim. TIOBE indeksissä, mutta se ei toki tarkoita etteikö sitä jo kentällä käytettäisi.

Kannattaisiko siis käyttää Kotlinia seuraavaan projektiin? Omalta puoleltani annan vahvan peukutuksen. Clojure uskovaiset tuskin kokevat halua kääntyä tänne, se on edelleen oma maailmansa. Java uskovaisten kannattaisi tehdä seuraava projekti ihan millä hyvänsä modernimmalla kielellä, Java on nykymuodossaan aika rasitettu ja päällelaastaroitu sekamelska, ja Scala, Clojure, ja Kotlin ovat kaikki huimia parannuksia siihen. Scala kielen pieni haitta on se että se oli kentällä aikaisin, ja nyt sen linjaus Java 8 mukaiseksi on vähän isompi operaatio. Scalassa on myös turhankin voimallisia tapoja ampua itseään jalkaan, jotka ovat Kotlinista tahallisesti poistettuja.

Kuten Scala, myös Kotlin on hyvä alusta jossa voit toteuttaa vapaasti haluamaasi yhdistelmää funktionaalista tai olio-ohjelmointityyliä. Voit esim. aloittaa iisisti perinteisemmällä Java oliokoodilla, ja hivuttaa itseäsi kohti korkeamman tason funktioita ja immutable, arvoja. Kotlin käyttöönotto on helppoa, ja sen voi perinteiseen tapaan aloittaa vaikkapa testipuolella. Kotlin toimii myös mukavasti esim. Spring Boot+REST alustana, ja sen saumaton yhteensopivuus olemassaolevien Java-kirjastojen kanssa tuo ratkaisua mm. tietokantojen kanssa pelaamiseen.

Itse ainakin käyttäisin. Rakastuin aikanaan Scalaan, ja Kotlin on Scalalle vähän samaa kuin Scala oli Javalle. Scala on edelleen paljonkin voimallisempi työkalu, ja kypsempi myös, mutta molemmat piirteet ovat kaksiteräisiä miekkoja. Ja Java-kieltä taas kukaan ei varmaan ihan ehdottoman innoissaan halua koodata. Sen paras argumentti lienee Cobol-mainen 20 vuoden tuoma maturiteetti, se on hyvä sveitsin armeijan linkkuveitsi siellä työkalupakin pohjalla. Ehkä sen olisi kielenä jo aika kuolla pois. Mutta toki maailmalta löytyy 10 miljoonaa enemmän tai vähemmän aktiivista koodaajaa jotka sitä ymmärtävät. Digitalisoinnin tarpeiden taas laajentuessa eksponentiaalisesti sekin on hyve.

 

Tuolta lisää:

https://kotlinlang.org/

 

Mainokset

Java 9 ja CORBA

Heh, niinpä. Olen kirjaillut aiemmin useammankin kerran tulevan Java 9:n ihmetyksen aiheista. Silmiin osui hauska artikkeli siitä miten viimeinkin CORBA, Common Object Request Broker, tuo kaikkien väylien ja hajautuksen edelläkävijä ja kaikkien sitä käyttäneiden inhokki, ei enää tule vakiovarusteena perus-Javassa.

Java 9 suuri uudistushan on modulaarisuus, ja sen tärkeimpänä osana ja ajurina Javan n. 20-megainen runtime modularisoidaan, siten että sieltä löytyy tiukka ydin-kernel, ja lukuisia moduuleita joita voi halunsa mukaan ottaa mukaan tai jättää ottamatta. Pitkän tähtäimen strategia on varmasti paluu mobiili ja IoT ympäristöihin uusin voimin.

Eli, oletuspaketti, root moduulit, ei sisällä enää tarpeetonta kuraa, ja osa tarpeellisistakin lähtee erilleen. Jos kaipaat CORBAA, saat sen takaisin kytkimellä:

-addmods java.corba

Hyvä huomata että vastaavia muita moduuleita ovat mm.:

java.activation
java.annotations.common
java.corba
java.transaction
java.xml.bind
java.xml.ws

Näyttäisi siis siltä että viimein Java menee tosissaan tiukalle dieetille. Java 9:stä kuulemme varmaan lisää tämän vuoden JavaOne seminaarissa San Franciscossa – mutta mielenkiintoa näyttäisi olevan. Varmaa on, että jatkossa on syytä opetella käyttämään moduulijärjestelmää ja sen kytkimiä – muuten ei vanhat Java-koodit enää edes käänny.

Toinen tutkaimiin osunut juttu on moneltakin taholta julistettu Java EE 8 kuolema. Oraclen panostus ja mielenkiinto sen suhteen näyttää olevan lopahtamassa. Mielenkiinnolla seuraan mitä tämä tarkoittaa, ja mitä tuo tullessaan. Tutkaimet herkkinä. Tämäkin selvinnee syksymmällä.

 

http://mail.openjdk.java.net/pipermail/jdk9-dev/2016-May/004309.html