Erst seit 2016 mit der Version 1.0 verfügbar, dennoch bereits hoch angesehen: Kotlin, eine Al­ter­na­ti­ve zu Java. Die ob­jekt­ba­sier­te Pro­gram­mier­spra­che stammt von JetBrains, einem tsche­chi­schen Un­ter­neh­men für Software-Ent­wick­lung. Sie überzeugt viele durch ihren schlanken Charakter und deshalb, weil sie nicht so oft Lauf­zeit­feh­ler pro­du­ziert – vor allem nicht die ge­fürch­te­ten Null­Poin­ter­Ex­cep­ti­ons. Besonders bei der Ent­wick­lung von Android-Apps ist Kotlin sehr beliebt. Aber auch als Aus­gangs­punkt für Ja­va­Script-An­wen­dun­gen erfreut sich die junge Pro­gram­mier­spra­che enormer Be­liebt­heit.

Kotlin ist eng an Java angelehnt: Zwar sind die beiden Pro­gram­mier­spra­chen nicht mit­ein­an­der kom­pa­ti­bel, dennoch wird Kotlin in Bytecode trans­for­miert, der wiederum von einer Java Virtual Machine (JVM) gelesen werden kann.

Anleitung für Kotlin – mit Bei­spie­len

Um mit Kotlin zu starten, kann der Compiler von der of­fi­zi­el­len Website her­un­ter­ge­la­den werden. Einfacher geht es mit einer Ent­wick­lungs­um­ge­bung (IDE): IntelliJ IDEA (auch von JetBrains), Eclipse (mit ent­spre­chen­dem Plug-in), NetBeans und Android Studio können bei­spiels­wei­se mit Kotlin umgehen.

Tipp

Die Her­stel­ler von Kotlin halten online eine Sandbox bereit, in der Sie alle Beispiele aus­pro­bie­ren können.

Pakete (Packages)

Zu Beginn eines Projekts im­por­tie­ren Sie die Pakete, die Sie zur Rea­li­sie­rung Ihres Vorhabens benötigen. Außerdem de­fi­nie­ren Sie das Package, an dem Sie gerade arbeiten. Packages enthalten Klassen und Funk­tio­nen.

package test.bar
import foo.bar
import footoo.bar as footoo

Um Probleme bei gleichen Namen zu vermeiden, können Sie Packages in Kotlin mit as um­be­nen­nen. Die Na­mens­ge­bung der Packages muss nicht der Ver­zeich­nis­struk­tur folgen, in der diese zu finden sind. Der Übersicht wegen empfiehlt sich aber dennoch dieses Vorgehen.

Hinweis

Kotlin lädt die wich­tigs­ten Packages au­to­ma­tisch in jedes Projekt.

Im Gegensatz zu Java können Sie bei Kotlin auch einzelne Funk­tio­nen aus anderen Paketen im­por­tie­ren. Hierfür gibt man den korrekten Pfad an:

import foo.bar.myFunction

An­schlie­ßend kann die Funktion ganz normal verwendet werden.

Tipp

Code­zei­len müssen in Kotlin nicht durch eine Mar­kie­rung – z. B. ein Semikolon – ab­ge­schlos­sen werden.

Variablen

Kotlin kennt zwei ver­schie­de­ne Arten von Variablen: Solche, die nur gelesen werden können und fest­ge­legt sind, werden mit val ein­ge­lei­tet. Andere, deren Wert man im Laufe des Programms verändern kann, leiten Sie mit var ein.

val name = "Clara Oswald"
var age = 22

Im Gegensatz zum fest­ste­hen­den Namen kann das Alter angepasst werden, etwa in einer Funktion.

Hinweis

In diesem Beispiel hat Kotlin den Typ des Werts der Variablen selbst fest­ge­legt. Es ist auch möglich, diese Basic Types konkret aus­zu­zeich­nen.

Ba­sis­ty­pen (Basic Types)

Kotlin arbeitet mit be­stimm­ten Typen für Variablen und Klassen. Bei jedem Typ handelt es sich um ein Objekt, und damit un­ter­schei­det sich Kotlin etwas von Java. Während die ältere Pro­gram­mier­spra­che primitive Typen erst in einen Wrapper packen muss, damit sie sich wie Objekte verhalten, ist das bei Kotlin nicht nötig. Hier sind wirklich alle Typen bereits Objekte.

Zahlen (Numbers)

In Kotlin können Sie Zahlen ohne eine bestimmte Mar­kie­rung einsetzen: Der Compiler versteht, dass es sich um Zah­len­wer­te halten soll. Kommas werden durch Punkte rea­li­siert. Wer möchte, kann auch he­xa­de­zi­ma­le Zahlen verwenden. Zur besseren Les­bar­keit lassen sich Tau­sen­der­trenn­zei­chen mit Un­ter­stri­chen dar­stel­len. Kotlin kennt ver­schie­de­ne Arten von Zahlen, die alle eine un­ter­schied­li­che maximale Größe annehmen können:

  • Long: 64 Bit
  • Int: 32 Bit
  • Short: 16 Bit
  • Byte: 8 Bit
  • Double: 64 Bit
  • Float: 32 Bit

Bei Double und Float handelt es sich um Gleit­kom­ma­zah­len, die sich in komplexen Be­rech­nun­gen anders verhalten als die Fest­kom­ma­zah­len. Wie alle Typen können Sie Zahlen konkret in Ihrem Code aus­zeich­nen.

val myNumber: Long = 40

Es ist möglich, dass Sie eine Zahl eines be­stimm­ten Typus zu einem anderen kon­ver­tie­ren.

val myInt = 600
val myLong= myInt.toLong()

Der Befehl toLong kon­ver­tiert den Int-Wert in einen Long-Wert. Analog funk­tio­niert der Befehl auch ab­ge­wan­delt für die anderen Typen von Numbers.

String

Bei einem String handelt es sich um Wörter oder ganze Sätze, also um Zei­chen­ket­ten. Um diese in Kotlin zu verwenden, setzen Sie das Ge­schrie­be­ne in doppelte An­füh­rungs­zei­chen. Möchten Sie mehrere Zeilen Text einbauen, sind drei doppelte An­füh­rungs­zei­chen je zu Beginn und zum Ende nötig (Raw String).

val myString = "Das ist ein einzeiliger String."
val myLongString = """Dies ist ein String,
der über mehrere Zeilen geht."""

Wie in vielen anderen Pro­gram­mier­spra­chen ist in Kotlin die Ver­wen­dung von Escape Cha­rac­ters möglich: Durch einen Backslash markieren Sie ein Zeichen, das nicht zum ei­gent­li­chen String gehört, sondern als Steu­er­zei­chen behandelt werden soll. Umgekehrt lassen sich durch den Backslash auch Zeichen in den String einfügen, die ei­gent­lich in Kotlin eine andere Bedeutung haben. Folgende Escape Cha­rac­ters sind möglich:

  • \t: Tab
  • \b: Backspace
  • \n: Neue Zeile
  • \r: Carriage Return (Wa­gen­rück­lauf)
  • \': Einfaches An­füh­rungs­zei­chen
  • \": Doppeltes An­füh­rungs­zei­chen
  • \\: Backslash
  • \$: Dol­lar­zei­chen

Das Dol­lar­zei­chen dient Ihnen in Strings dazu, Platz­hal­ter ein­zu­set­zen. Diese kann man in einem vor­he­ri­gen Schritt als Variable festlegen. So wird der Platz­hal­ter dann in der Ausgabe durch einen tat­säch­li­chen Wert ersetzt.

val author = "Sandra"
val myString = "Dieser Text stammt von $author"

Zeichen (Cha­rac­ters)

Für einzelne Zeichen stellt Kotlin neben Strings auch den spe­zi­el­len Datentyp Character zur Verfügung. Statt diese al­ler­dings in doppelte An­füh­rungs­zei­chen zu setzen, verwendet man einfache An­füh­rungs­zei­chen.

var model = 'A'

Boolean

Der Basic Type Boolean gibt einen Wahr­heits­wert wieder, der entweder wahr (true) oder falsch (false) sein kann.

Arrays

In Kotlin ist ein Array eine Sammlung von Daten. Ein Array bilden Sie mit arrayOf() oder Array(). Die erste Funktion gestaltet sich simpel:

val myArray1 = arrayOf(0, 1, 2, 3, 4, 5)

So erzeugt man ein Array mit den Ziffern von 1 bis 5. In diesen Samm­lun­gen können aber auch andere Typen wie Strings und Booleans un­ter­ge­bracht werden – sogar gemischt. Möchte man das Array auf einen Typ be­schrän­ken, gibt man dies in der Funktion mit an.

val myArray2 = arrayOf<int>(10, 20, 30)</int>
val myArray3 = booleanArrayOf(true, true, false)

Der Kotlin-Con­s­truc­tor Array() gestaltet sich komplexer: Hier müssen Sie auch die Länge und eine Lambda-Funktion angeben.

val myArray4 = Array(6, { i -> i })

Der Con­s­truc­tor erzeugt ein Array mit sechs Stellen und beginnt bei null: 0, 1, 2, 3, 4, 5.

Hinweis

Mehr zu Con­s­truc­tors und Lambdas erfahren Sie weiter unten im Text.

Jeder Eintrag in einem Array wird indiziert und kann über diesen Index auf­ge­ru­fen werden. Dabei verwendet man eckige Klammern und gibt in diesen die Stelle an, die der Eintrag in der Auf­lis­tung innehat.

fun main() {
	val myArray5 = arrayOf("Jan", "Maria", "Samuel")
	println(myArray5[2])
}
Hinweis

Die Funktion wird in diesem Fall "Samuel" ausgeben, denn die Zählung beginnt mit 0.

Ope­ra­to­ren

Wie man es aus vielen anderen Pro­gram­mier­spra­chen kennt, arbeitet auch Kotlin mit ver­schie­de­nen Ope­ra­to­ren, die Sie in Ihren Quellcode einbauen können. Dazu gehören ma­the­ma­ti­sche Ope­ra­to­ren (+, -, *, /, %), Ver­gleichs­ope­ra­to­ren (<, >, <=, >=, ==, !=) und logische Ope­ra­to­ren (&&, ||, !). Eng mit den Ope­ra­to­ren verwandt sind so­ge­nann­te Keywords: Begriffe, die eine feste Bedeutung in Kotlin haben und nicht um­in­ter­pre­tiert werden können.

Tipp

Eine voll­stän­di­ge Liste aller Keywords und Ope­ra­to­ren finden Sie in der of­fi­zi­el­len Do­ku­men­ta­ti­on von Kotlin.

Ranges

In Kotlin be­schreibt eine Range einen Typ, der von einem be­stimm­ten Punkt bis zu einem weiteren reicht. Um eine Range zu erzeugen, wendet man den Operator .. an oder nutzt die Funk­tio­nen rangeTo() bzw. downTo(). Die Variante mit zwei Punkten hin­ter­ein­an­der kann hoch­zäh­len. Mit den beiden Funk­tio­nen hingegen de­fi­nie­ren Sie in eine Richtung.

val range1 = 1..5
val range2 = 1.rangeTo(5)
val range3 = 5.downTo(1)

In diesen einfachen Versionen erzeugen Sie eine Range mit Einer-Schritten. Um die Schritt­grö­ße an­zu­pas­sen, verwenden Sie zu­sätz­lich die step-Funktion.

val range4 = 0..10 step(2)

Um einzelne Daten in der Range an­zu­spre­chen, verwenden Sie den in-Operator. So können Sie bei­spiels­wei­se eine Abfrage oder auch eine Schleife erzeugen. Um zu über­prü­fen, ob ein Wert nicht Teil der Range ist, nutzt man den Operator !in.

val range5 = 0..10
fun main() {
	for (n in range5) {
		println(n)
	}
	if (7 in range5) {
		println("yes")
	}
	if (12 !in range5) {
		println("no")
	}
}
Hinweis

Mehr zu Funk­tio­nen (fun), Schleifen (for) und Be­din­gun­gen (if) erfahren Sie weiter unten im Text.

Funk­tio­nen (Functions)

Kotlin-Functions werden immer mit dem Befehl fun erstellt. Im Anschluss de­fi­nie­ren Sie den Namen der Funktion, welche Argumente diese enthält und schließ­lich, was sie macht.

fun div(a: Int, b: Int): Int {
	return a/b
}
fun main() {
	println(div(100, 2))
}

Wir de­fi­nie­ren zuerst die Funktion div (für Division) mit zwei Int-Pa­ra­me­tern a und b. Die Funktion soll uns das Ergebnis aus der Division von a durch b geben, ebenfalls in Form einer Int-Variablen. In der main-Funktion schließ­lich rufen wir die zuvor de­fi­nier­te Funktion auf, übergeben ihr konkrete Werte und lassen das Ergebnis durch println (print line) in der Konsole anzeigen. Kotlin führt den Inhalt von main() au­to­ma­tisch aus. Diese Funktion stellt den Ein­stiegs­punkt in ein Kotlin-Programm dar.

Fakt

Außerhalb von Funk­tio­nen ak­zep­tiert Kotlin keine Befehle. Nur De­kla­ra­tio­nen sind dort erlaubt.

In Kotlin lassen sich Functions, die nur eine Zeile Code umfassen, ver­ein­facht dar­stel­len. Statt ge­schweif­te Klammern zu öffnen, eine neue, ein­ge­scho­be­ne Zeile zu schreiben und die Klammer wieder zu schließen, setzt man ein Gleich­heits­zei­chen ein. Dabei wird zu­sätz­lich auf den Befehl return ver­zich­tet.

fun div(a: Int, b: Int): Int = a/b
fun main() = println(div(100, 2))

Um einen Fehler durch fehlende Parameter zu vermeiden, können Sie beim De­fi­nie­ren der Funktion Stan­dard­wer­te angeben. Lässt man beim Aufrufen der Funktion die ent­spre­chen­den Parameter frei, kommen die Default-Werte zum Einsatz.

fun div(a: Int = 10, b: Int = 5): Int = a/b
fun main() = println(div())

Lambdas

Bei einer Lambda-Funktion (oder anonymen Funktion) handelt es sich um eine Funktion, die weder zu einer Klasse noch zu einem Objekt gehört. Lambdas werden direkt in anderen Funk­tio­nen oder Variablen un­ter­ge­bracht. Man ruft sie auf, ohne das Keyword fun zu verwenden. Lambdas lassen sich im Prinzip wie Variablen des Typs val einsetzen und werden auch so erzeugt.

fun main() {
	val myMessage = { println("Hello world!") }
	myMessage()
}

Lambda-Ex­pres­si­ons in Kotlin müssen immer in ge­schweif­te Klammern gesetzt werden. Lambdas können auch Funk­ti­ons­ar­gu­men­te ver­ar­bei­ten. Diese sind durch einen Pfeil ge­kenn­zeich­net, der die Parameter vom Kern des Ausdrucks trennt.

fun main() {
    val div = {a: Int, b: Int -> a/b}
    println(div(6,2))
}

Klassen (Classes)

Genau wie in Java sind Klassen in Kotlin Samm­lun­gen von Daten und Funk­tio­nen. Um eine Klasse zu de­fi­nie­ren, setzt man einfach das Stichwort class ein. An­schlie­ßend kann man die neue Klasse mit In­for­ma­tio­nen füllen.

class Tardis {
	var year: Int
	var place: String
	constructor(year: Int, place: String) {
		this.year = year
		this.place = place
	}
}

In Kotlin ist der Con­s­truc­tor eine Funktion, die man für die Er­stel­lung von Objekten benötigt. Dafür kennt die Pro­gram­mier­spra­che Primary und Secondary Con­s­truc­tors. Primary Con­s­truc­tors sind eine prak­ti­sche Kurz­schreib­wei­se, während Secondary Con­s­truc­tors der Schreib­wei­se in vielen anderen ob­jekt­ori­en­tier­ten Sprachen ähneln, darunter Java. Diese zweite Variante sehen Sie in obigem Beispiel.

Es gibt aber auch die Mög­lich­keit, den Secondary Con­s­truc­tor aus­zu­las­sen und statt­des­sen einen Primary Con­s­truc­tor einsetzen. Diesen schreiben Sie direkt in die Kopfzeile der Klasse und geben dabei auch die Parameter der Klasse mit an. Dies reduziert die Anzahl der Code­zei­len deutlich.

class Tardis constructor(var year: Int, var place: String)

Wenn Sie keine zu­sätz­li­chen Angaben in Bezug auf die Sicht­bar­keit der Klasse machen möchten (public, private, protected), können Sie auch ganz auf die Nennung des Keywords ver­zich­ten.

class Tardis (var year: Int, var place: String)

Alle drei Code­bei­spie­le erzeugen das gleiche Ergebnis.

Diese Klasse können Sie nun in Ihrem weiteren Quelltext einsetzen und mit konkreten Werten füttern.

val tardis1 = Tardis(2133, "Dunlop Station")
val tardis2 = Tardis(1885, "Northhampton")

Wie in den meisten ob­jekt­ori­en­tier­ten Sprachen üblich, können Sie auf die Ei­gen­schaf­ten und Methoden eines Objekts direkt zugreifen, indem Sie einen Punkt und den Namen der Ei­gen­schaft oder Methode hinter den des Objekts setzen.

class Tardis (var year: Int, var place: String)
val tardis1 = Tardis(2133, "Dunlop Station")
val tardis2 = Tardis(1885, "Northhampton")
fun main() {
    println(tardis1.year)
}

Eine Be­son­der­heit in Kotlin stellt die Data Class dar. Diese Klas­sen­art ist dazu gedacht, nur Daten zu speichern. Prin­zi­pi­ell reicht hierfür eine Codezeile aus.

data class User (var username: String, var name: String, var age: Int)

Diese Klasse kann direkt ein­ge­setzt werden.

data class User (var username: String, var name: String, var age: Int)
fun main() {
    val user1 = User ("River Song", "Melody Pond", 200)
    println("Username: " + user1.username)
    println("Name: " + user1.name)
    println("Age: " + user1.age)
}

Objekte (Objects)

Objekte sind in Kotlin Instanzen, die so nur ein einziges Mal definiert sein können (Singleton). Sie enthalten in der Regel Variablen und Funk­tio­nen. Man kreiert ein Objekt – ähnlich wie eine Klasse – prin­zi­pi­ell mit nur einer Zeile Code. Dann ist das Objekt al­ler­dings leer. Inhalt geben Sie dem Objekt in dessen Körper.

object myObject {
	fun sum(a: Int, b: Int): Int {
		return a+b
	}
}

Schleifen (Loops)

In Kotlin stehen Ihnen drei ver­schie­de­ne Schlei­fen­ar­ten zur Verfügung: while, do..while und for. Diese verhalten sich wie ihre Äqui­va­len­te in anderen Pro­gram­mier­spra­chen. Eine while-Schleife läuft so lang, bis eine fest­ge­leg­te Bedingung eintritt.

fun main() {
    var n = 1
    while (n <= 10) {
        println(n++)
    }
}

Die do..while-Schleife verhält sich ganz ähnlich zur Variante mit while. Der Un­ter­schied liegt darin, dass der Inhalt der Schleife min­des­tens einmal durch­lau­fen wird, da die Über­prü­fung erst am Ende statt­fin­det.

fun main() {
    var n = 1
    do {
        n++
    }	
    while (n < 1)
    println(n)
}

Die for-Schleife läuft so lang, wie eine Bedingung wahr bleibt.

val myRange = 0..10
fun main() {
	for (n in myRange) {
		print("$n ")
	}
}

Be­din­gun­gen (Con­di­ti­ons)

Kotlin kennt drei ver­schie­de­ne Mög­lich­kei­ten, um bedingte An­wei­sun­gen bzw. Ver­zwei­gun­gen um­zu­set­zen: if, if..else und when. Die Abfrage if lässt den Computer eine Aufgabe erledigen, falls die Bedingung zutrifft.

val whoCompanion = arrayOf("Bill Potts", "Clara Oswald", "Amy Pond", "Martha Jones", "Donna Noble", "Rose Tyler")
fun main() {
    if ("Rose Tyler" in whoCompanion) {
        print("yes")
    }
}

Mit else fügen Sie eine Aktion hinzu, die aus­ge­führt werden soll, wenn die Bedingung nicht zutrifft.

val whoCompanions9 = arrayOf("Rose Tyler")
val whoCompanions10 = arrayOf("Martha Jones", "Donna Noble", "Rose Tyler")
val whoCompanions11 = arrayOf("Clara Oswald", "Amy Pond")
val whoCompanions12 = arrayOf("Bill Potts", "Clara Oswald")
fun main() {
    var whoCompanion = "Clara Oswald"
    if (whoCompanion in whoCompanions9) {
        print("yes")
    }
    else {
        print("no")
    }
}

Der Ausdruck when schließ­lich ist eine Be­son­der­heit von Kotlin: Abhängig von ver­schie­de­nen Zuständen werden un­ter­schied­li­che Aktionen durch­ge­führt. Damit ähnelt der when-Ausdruck dem, was in anderen Pro­gram­mier­spra­chen switch löst; er arbeitet aber präziser.

Im Körper von when bringen Sie die un­ter­schied­li­chen Über­prü­fungs­fäl­le unter. Diese stehen immer in Zu­sam­men­hang mit einer de­fi­nier­ten Variablen.

var age = 17
fun main() {
    when {
     	age > 18 -> println("Du bist zu alt!")
     	age == 18 -> println("Schon erwachsen!")
     	age == 17 -> println("Herzlich willkommen!")
     	age <= 16 -> println("Du bist zu jung!")
    }
}

Das Argument kann al­ler­dings auch direkt an when übergeben werden und muss dann nicht jedes Mal erneut im Körper genannt werden. Darüber hinaus kann eine einzelne Bedingung auch mehrere Aktionen auslösen. Dafür erstellen Sie mit ge­schweif­ten Klammern einen neuen Body. Um un­er­war­te­te Fälle aus­zu­schlie­ßen, hilft Ihnen else.

fun multi(a: Int, b: Int, c: Int): Int {
    return a*b*c
}
fun main() {
    val d = "yes"
    when (d) {
        "no" -> println("Keine Berechnung")
        "yes" -> {
            println("Starte Berechnung") 
            println(multi(5, 2, 100))
            println("Berechnung beendet")
        }
    else -> println("Falsche Eingabe")    
    }
}

Nulla­bi­li­ty

Ein großer Un­muts­fak­tor bei der Pro­gram­mie­rung mit Java ist der Fehler Null­Poin­ter­Ex­cep­ti­on. Dieser tritt auf, wenn man auf ein Objekt verweist, dessen Wert null ist. Kotlin umgeht dieses Problem, indem es gar nicht erst zulässt, dass Variablen den Wert null annehmen. Sollte der Fall eintreten, erscheint schon beim Kom­pi­lie­ren der Hinweis: „Null can not be a value of a non-null type String“ – oder eine ent­spre­chend andere Warnung.

Nun gibt es aber Momente, in denen möchte man den null-Wert bewusst einsetzen. Dafür verwendet Kotlin den Safe Call Operator: ?.

fun main() {
	var password: String? = null
	print(password)
}

Hiermit erlauben Sie Kotlin explizit, dass null ak­zep­ta­bel ist. Das Programm wird an­schlie­ßend null ausgeben. Möchten Sie al­ler­dings eine bestimmte Ei­gen­schaft der Variable an­spre­chen, müssen Sie den Safe Call Operator erneut einsetzen.

fun main() {
	var password: String? = null
	print(password?.length)
}

Auch dieser Code wird wieder null pro­du­zie­ren, aber eben keinen Error – das Programm läuft. Etwas eleganter ist es, wenn Sie einen Al­ter­na­tiv­wert angeben. Dafür verwenden Sie den so­ge­nann­ten Elvis-Operator: ?: – so benannt, weil man die Zei­chen­fol­ge als Smiley mit Haartolle lesen kann.

fun main() {
    val firstName = null
    val lastName = "Pond"
	val name: String = firstName?: "Vorname fehlt" + " " + lastName?: "Nachname fehlt"
	print(name)
}

In diesem Beispiel werden Hinweise angezeigt, wenn eine Variable den Wert null annimmt.

Zum Hauptmenü