Wat is Kotlin? Het Java-alternatief uitgelegd

Kotlin is een gratis, open source, statisch getypeerde "pragmatische" programmeertaal voor algemeen gebruik, oorspronkelijk ontworpen voor de JVM (Java Virtual Machine) en Android, die objectgeoriënteerde en functionele programmeerfuncties combineert. Het is gericht op interoperabiliteit, veiligheid, duidelijkheid en ondersteuning van tools. Versies van Kotlin die zijn gericht op JavaScript ES5.1 en native code (met behulp van LLVM) voor een aantal processors zijn ook in productie.

Kotlin is ontstaan ​​bij JetBrains, het bedrijf achter IntelliJ IDEA, in 2010 en is sinds 2012 open source. Het Kotlin-team heeft momenteel meer dan 90 fulltime leden van JetBrains en het Kotlin-project op GitHub heeft meer dan 300 medewerkers. JetBrains gebruikt Kotlin in veel van zijn producten, waaronder zijn vlaggenschip IntelliJ IDEA.

Kotlin als een beknoptere Java-taal

Op het eerste gezicht lijkt Kotlin een meer beknopte en gestroomlijnde versie van Java. Beschouw de bovenstaande schermafbeelding, waar ik een Java-codevoorbeeld (links) automatisch naar Kotlin heb geconverteerd. Merk op dat de hersenloze herhaling die inherent is aan het instantiëren van Java-variabelen, is verdwenen. Het Java-idioom

StringBuilder sb = nieuwe StringBuilder ();

Wordt in Kotlin

val sb = StringBuilder ()

U kunt zien dat functies zijn gedefinieerd met het funtrefwoord en dat puntkomma's nu optioneel zijn wanneer er nieuwe regels aanwezig zijn. Het valsleutelwoord declareert een alleen-lezen eigenschap of lokale variabele. Evenzo vardeclareert het sleutelwoord een veranderlijke eigenschap of lokale variabele.

Toch is Kotlin sterk getypeerd. De valen varzoekwoorden kunnen alleen worden gebruikt wanneer het type kan worden afgeleid. Anders moet u het type aangeven. Type-inferentie lijkt te verbeteren met elke release van Kotlin.

Bekijk de functieverklaring bovenaan beide panelen. Het retourtype in Java gaat vooraf aan het prototype, maar in Kotlin volgt het prototype op, afgebakend met een dubbele punt zoals in Pascal.

Het is niet helemaal duidelijk uit dit voorbeeld, maar Kotlin heeft de Java's eis dat functies klasseleden zijn, versoepeld. In Kotlin kunnen functies op het hoogste niveau in een bestand worden gedeclareerd, lokaal binnen andere functies, als een lidfunctie binnen een klasse of object en als een uitbreidingsfunctie. Uitbreidingsfuncties bieden de C # -achtige mogelijkheid om een ​​klasse uit te breiden met nieuwe functionaliteit zonder te moeten erven van de klasse of elk type ontwerppatroon zoals Decorator te gebruiken.

Voor Groovy-fans implementeert Kotlin bouwers; in feite kunnen Kotlin-bouwers worden getypeerd. Kotlin ondersteunt gedelegeerde eigenschappen, die kunnen worden gebruikt om luie eigenschappen, waarneembare eigenschappen, veto-eigenschappen en toegewezen eigenschappen te implementeren.

Veel asynchrone mechanismen die in andere talen beschikbaar zijn, kunnen als bibliotheken worden geïmplementeerd met behulp van Kotlin-coroutines. Dit omvat async/ awaituit C # en ECMAScript, kanalen en selecteer uit Go, en generators/ yielduit C # en Python.

Functioneel programmeren in Kotlin

Het toestaan ​​van functies op het hoogste niveau is nog maar het begin van het functionele programmeerverhaal voor Kotlin. De taal ondersteunt ook functies van hogere orde, anonieme functies, lambda's, inline-functies, sluitingen, staartrecursie en generieke geneesmiddelen. Met andere woorden, Kotlin heeft alle kenmerken en voordelen van een functionele taal. Beschouw bijvoorbeeld de volgende functionele Kotlin-idiomen.

Een lijst filteren in Kotlin

val positives = list.filter {x -> x> 0}

Gebruik voor een nog kortere uitdrukking itals er maar één parameter in de lambda-functie is:

val positives = list.filter {it> 0}

Een kaart / lijst met paren doorkruisen in Kotlin

voor ((k, v) in kaart) {println ("$ k -> $ v")}

ken  v kan van alles worden genoemd.

Bereik gebruiken in Kotlin

for (i in  1..100) {...} // gesloten bereik: omvat 100

for (i in  1 tot 100) {...} // halfopen bereik: bevat geen 100

voor (x in  2..10 stap 2) {...}

voor (x in  10 omlaag naar 1) {...}

if (x in  1..10) {...}

De bovenstaande voorbeelden tonen zowel het  for trefwoord als het gebruik van bereiken.

Hoewel Kotlin een volwaardige functionele programmeertaal is, behoudt het de meeste objectgeoriënteerde aard van Java als alternatieve programmeerstijl, wat erg handig is bij het converteren van bestaande Java-code. Kotlin heeft klassen met constructeurs, samen met geneste, innerlijke en anonieme inwendige klassen, en het heeft interfaces zoals Java 8. Kotlin heeft geen een heeft newtrefwoord. Om een ​​klasse-instantie te maken, roept u de constructor aan, net als een gewone functie. We zagen dat in de bovenstaande schermafbeelding.

Kotlin heeft een enkele overerving van een genoemde superklasse en alle Kotlin-klassen hebben een standaard superklasse Any, die niet hetzelfde is als de Java-basisklasse java.lang.Object. Anybevat slechts drie vooraf gedefinieerde lidfuncties: equals(), hashCode()en toString().

Kotlin-klassen moeten worden gemarkeerd met het opentrefwoord om andere klassen ervan te laten erven; Java-klassen zijn min of meer het tegenovergestelde, omdat ze kunnen worden overgenomen, tenzij ze zijn gemarkeerd met het finaltrefwoord. Om een ​​superklasse-methode te overschrijven, moet de methode zelf worden gemarkeerd openen moet de subklassemethode worden gemarkeerd override. Dit past allemaal in de filosofie van Kotlin om dingen expliciet te maken in plaats van te vertrouwen op standaardinstellingen. In dit specifieke geval kan ik zien waar Kotlin's manier om basisklasse-leden expliciet te markeren als open voor overerving en afgeleide klasleden als overschrijvingen verschillende soorten veelvoorkomende Java-fouten vermijdt.

Veiligheidsvoorzieningen in Kotlin

Over het vermijden van veelvoorkomende fouten gesproken, Kotlin is ontworpen om het gevaar van null-pointerreferenties te elimineren en de verwerking van null-waarden te stroomlijnen. Het doet dit door een nullonwettig te maken voor standaardtypen, nullable-typen toe te voegen en snelkoppelingsnotaties te implementeren om tests voor null af te handelen.

Een gewone variabele van het type  kan bijvoorbeeld niet bevatten  :String null

var a: String = "abc"

a = null // compilatiefout

Als u null-waarden moet toestaan, bijvoorbeeld om SQL-queryresultaten vast te houden, kunt u een nullable-type declareren door een vraagteken aan het type toe te voegen, bijv String?.

var  b: String?

b = null  // ok

De beveiligingen gaan een beetje verder. Je kunt straffeloos een niet-nullabel type gebruiken, maar je moet een nullable-type testen op null-waarden voordat je het gebruikt.

Om de uitgebreide grammatica te vermijden die normaal nodig is voor nul-testen, introduceert Kotlin een veilige aanroep , geschreven ?.. Retourneert bijvoorbeeld if niet en anders. Het type van deze uitdrukking is .b?.length b.lengthbnullnullInt?

Met andere woorden, b?.lengthis een snelkoppeling voor if (b != null) b.length else null. Deze syntaxis sluit mooi aan en elimineert nogal wat prolixlogica, vooral wanneer een object werd gevuld vanuit een reeks databasequery's, die allemaal mogelijk mislukt waren. bob?.department?.head?.nameZou bijvoorbeeld de naam van het afdelingshoofd van Bob retourneren als Bob, de afdeling en het afdelingshoofd allemaal niet nul zijn.

Om een ​​bepaalde bewerking alleen uit te voeren voor niet-nulwaarden, kunt u de veilige oproep-operator gebruiken in ?.combinatie met  let:

val listWithNulls: List = listOf ("A", null)

voor (item in listWithNulls) {

      item? .let {println (it)} // drukt A af en negeert null}

Vaak wilt u een geldige maar speciale waarde retourneren van een nullable-expressie, meestal zodat u deze kunt opslaan in een niet-nullabel type. Er is een speciale syntaxis hiervoor, de Elvis-operator genaamd (ik maak geen grapje), geschreven ?:.

val l = b? .lengte?: -1

is het equivalent van 

val l: Int = if (b! = null) b. lengte anders -1

In dezelfde geest laat Kotlin de gecontroleerde uitzonderingen van Java weg, die werpbare omstandigheden zijn die moeten worden opgevangen. Bijvoorbeeld de JDK-handtekening

Appendable append (CharSequence csq) genereert  IOException;

vereist dat u IOExceptionelke keer dat u een appendmethode aanroept, opvangt:

proberen {

  log.append (bericht)

}

catch (IOException e) {

  // Doe iets met uitzondering

}

De ontwerpers van Java dachten dat dit een goed idee was, en het was een nettowinst voor speelgoedprogramma's, zolang de programmeurs maar iets zinnigs in de catchclausule implementeerden . Maar al te vaak in grote Java-programma's, echter, zie je code waarin de verplichte catchclausule bevat niets anders dan een reactie: //todo: handle this. Dit helpt niemand, en gecontroleerde uitzonderingen bleken een nettoverlies te zijn voor grote programma's.

Kotlin coroutines

Coroutines in Kotlin zijn in wezen lichtgewicht draden. Je start ze met de launchcoroutine builder in de context van sommigen CoroutineScope. Een van de meest bruikbare coroutine-scopes is runBlocking{}, wat van toepassing is op de scope van het codeblok.

importeer kotlinx.coroutines. *

fun main () = runBlocking {// this: CoroutineScope

    launch {// lanceer een nieuwe coroutine in het kader van runBlocking

        delay (1000L) // niet-blokkerende vertraging van 1 seconde

        println ("Wereld!")

    }

    println ("Hallo,")

}

Deze code produceert de volgende uitvoer, met een vertraging van één seconde tussen de regels:

Hallo,

Wereld!

Kotlin voor Android

Tot mei 2017 waren Java en C ++ de enige officieel ondersteunde programmeertalen voor Android. Google kondigde officiële ondersteuning aan voor Kotlin op Android op Google I / O 2017, en vanaf Android Studio 3.0 is Kotlin ingebouwd in de Android-ontwikkeltoolset. Kotlin kan met een plug-in worden toegevoegd aan eerdere versies van Android Studio.

Kotlin compileert naar dezelfde bytecode als Java, werkt op natuurlijke wijze samen met Java-klassen en deelt zijn tooling met Java. Omdat er geen overhead is voor het heen en weer bellen tussen Kotlin en Java, is het logisch om Kotlin stapsgewijs toe te voegen aan een Android-app die momenteel in Java zit. De weinige gevallen waarin de interoperabiliteit tussen Kotlin en Java-code niet goed genoeg is, zoals Java set-only eigenschappen, komen zelden voor en zijn gemakkelijk te verhelpen.

Pinterest was het affichekind voor Android-apps dat al in november 2016 in Kotlin werd geschreven, en het werd prominent vermeld op Google I / O 2017 als onderdeel van de aankondiging van Kotlin. Bovendien citeert het Kotlin-team graag de apps Evernote, Trello, Square en Coursera voor Android.

Kotlin versus Java

De vraag of je Kotlin of Java moet kiezen voor nieuwe ontwikkeling komt veel voor in de Android-gemeenschap sinds de aankondiging van Google I / O, hoewel mensen de vraag al stelden in februari 2016 toen Kotlin 1.0 werd uitgebracht. Het korte antwoord is dat Kotlin-code veiliger en beknopter is dan Java-code, en dat Kotlin- en Java-bestanden naast elkaar kunnen bestaan ​​in Android-apps, zodat Kotlin niet alleen nuttig is voor nieuwe apps, maar ook voor het uitbreiden van bestaande Java-apps.

Het enige overtuigende argument dat ik heb gezien om voor Java te kiezen boven Kotlin, zou zijn voor het geval van complete nieuwkomers op het gebied van Android-ontwikkeling. Voor hen kan er een hindernis zijn die overwonnen moet worden, aangezien historisch gezien de meeste Android-documentatie en voorbeelden in Java zijn. Aan de andere kant is het converteren van Java naar Kotlin in Android Studio een kwestie van het plakken van de Java-code in een Kotlin-bestand.

Voor bijna iedereen die Android-ontwikkeling doet, zijn de voordelen van Kotlin overtuigend. De typische tijd die een Java-ontwikkelaar nodig heeft om Kotlin te leren, is een paar uur - een kleine prijs die moet worden betaald om nulreferentiefouten te elimineren, uitbreidingsfuncties in te schakelen, functionele programmering te ondersteunen en coroutines toe te voegen. De typische ruwe schatting geeft een vermindering van ongeveer 40 procent aan in het aantal regels code van Java naar Kotlin.