Kotlin ist eine plattformübergreifende, statisch typisierte Programmiersprache, die in Bytecode für die Java Virtual Machine (JVM) übersetzt wird, aber auch in JavaScript-Quellcode, in WebAssembly oder (mittels LLVM) in Maschinencode umgewandelt werden kann. Kotlin lässt sich außerdem zur Entwicklung von Android- und iOS-Apps verwenden. Google unterstützt seit 2017 offiziell die Entwicklung von Android-Apps in Kotlin, und diese ist seit Mai 2019 die dafür bevorzugte Sprache.
Entwicklung Hauptsächlich wurde die Sprache von den damals in Sankt Petersburg ansässigen JetBrains-Programmierern entwickelt. Daher stammt auch der Name: Kotlin ist eine Insel vor St. Petersburg. Nach einem Jahr Entwicklung stellte JetBrains im Juli 2011 das Projekt „Kotlin“ der Öffentlichkeit als neue Sprache für die JVM vor.Hello World Im Februar 2012 veröffentlichte JetBrains den Quellcode unter einer Apache-2-Lizenz. Am 15. Februar 2016 wurde die Version 1.0 von Kotlin veröffentlicht. Diese Version wird als erstes offizielles Stable-Release betrachtet.
Der leitende Entwickler Dmitry Jemerov erklärte, dass die meisten Sprachen nicht die Merkmale zeigten, nach denen sie gesucht hätten, mit Ausnahme von Scala. Diese jedoch habe einen langsamen Compiler. Daher war eines der erklärten Ziele für Kotlin die hohe Kompiliergeschwindigkeit, wie man sie von Java her kenne.
Tools Auch die von JetBrains entwickelte IDE IntelliJ IDEA unterstützt seit der Version 15 Kotlin nativ via eines Plug-ins. Für Eclipse und Visual Studio Code stehen ebenfalls Plugins zur Verfügung. Es existieren zudem Plugins für Apache Maven und Gradle und ein Task für Apache Ant. Die offizielle Android-Entwicklungsumgebung Android Studio unterstützt von Version 3.0 an Kotlin als native Sprache zum Entwickeln von Android-Apps.
Im Java-Umfeld gibt es zahlreiche Frameworks und Bibliotheken, die bei der Test-Erstellung helfen. Da Kotlin vollständig interoperabel mit Java ist, können alle diese Tools ohne Weiteres für Tests von Kotlin-Code verwendet werden. Daneben existieren auch native Test-Frameworks für Kotlin wie z. B. kotlin-test.
Syntax Die Sprache ist syntaktisch nicht zu Java kompatibel, aber so gestaltet, dass sie mit Java-Code interoperieren kann. Außerdem nutzt sie bestehenden Code der Java Class Library (JCL), z. B. das Java Collections Framework (JCF).
Anders als in Java wird bei Kotlin der Datentyp einer Variable bei ihrer Deklaration nicht vor dem Variablennamen, sondern danach, abgetrennt durch einen Doppelpunkt, notiert. Allerdings unterstützt Kotlin auch Typinferenz, sodass der Typ oft auch weggelassen werden kann, wenn er aus dem Zusammenhang klar ist. Als Anweisungsende genügt der Zeilenumbruch, ein Semikolon ist hierbei nur notwendig, wenn eine Zeile aus mehreren Anweisungen besteht. Zusätzlich zu Klassen und Methoden (in Kotlin: member functions) aus der objektorientierten Programmierung unterstützt Kotlin prozedurale Programmierung unter Verwendung von Funktionen, sowie bestimmte Aspekte der funktionalen Programmierung. Als Einstiegspunkt dient wie bei C u. ä. eine Main-Funktion.
Hallo Welt Ein Programm, das die Zeichenkette „Hallo Welt“ ausgibt. fun main() { // Einsprungpunkt (Main-Funktion) println("Hallo Welt!") // Gib den String 'Hallo Welt!' aus }
Funktionen // Definition einer Funktion "funktionsBeispiel" fun funktionsBeispiel() { // ... }
// Funktion mit zwei Argumenten und einem Rückgabewert fun add(x: Int, y: Int): Int { return x + y }
// Besteht eine Funktion aus nur einem Ausdruck, dürfen die geschweiften Klammern, der Rückgabetyp und das "return" weggelassen werden. fun add2(x: Int, y: Int) = x + y
// Einsprungpunkt (Main-Funktion) fun main(args: Array<String>) { // Definition einer verschachtelten Funktion, die nur in main aufgerufen werden kann. fun test() { println("Hello World!")
// Aufrufen der Funktion test() }
Klassen und Objekte // Definition einer Beispielklasse class KlassenBeispiel( // Argumente x: Float, var text: String ) { // Attribute werden wie eine Variable in der Klasse definiert val zahl = x.toInt()
// init-Block init { println("Klasse wurde initialisiert mit Float $x")
// Interne Methode fun textUmdrehen() { text = text.reversed()
// Methode mit Rückgabewert fun ersteXTextBuchstaben(): String { return text.slice(0..<zahl)
fun main() { val objekt = KlassenBeispiel(4f, "Hallo Wiki") // -> Klasse wurde initialisiert mit Float 4.0
println("Zahl ist ${objekt.zahl}, Text ist ${objekt.text}") // -> Zahl ist 4, Text ist Hallo Wiki
objekt.textUmdrehen() println(objekt.text) // -> ikiW ollaH
println(objekt.ersteXTextBuchstaben()) // -> ikiW }
Kontrollstrukturen Kotlin unterstützt die gängigen Kontrollstrukturen.
If-Anweisung // Weist der schreibgeschützten lokalen Variable 'x' die Tastatureingabe (standard input stream) als Integer-Wert zu. val x = readLine()!!.toInt()
// if..else-Anweisung, die prüft, ob der Integer-Wert größer, kleiner oder gleich 0 ist. // Mit Ausgabe von Text auf der Konsole. if (x > 0) print("positiv") else if (x < 0) print("negativ") else print("0")
// Int-Eingabe: 10 -> String-Ausgabe: positiv
When-Anweisung Die when-Anweisung dient dem Pattern Matching. Nicht spezifizierte Fälle können mit „else“ abgefangen werden (vergleichbar mit „default“ bei switch-case-Anweisungen in Java). // Weist der schreibgeschützten lokalen Variable 'x' die Tastatureingabe (standard input stream) als Integer-Wert zu. val x = readLine()!!.toInt()
when (x) { 1 -> print("x == 1") 2 -> print("x == 2") 3, 4 -> print("x == 3 oder x == 4") in 5..7 -> print("x zwischen 5 und 7") else -> print("x ist kleiner als 1 oder größer als 7.") }
Repeat-Anweisung // Wiederholt die Funktionsanweisung 2x repeat(2) { println("Hello Wiki") } // Hello Wiki // Hello Wiki
For-Schleife // Iteriert i innerhalb der 7-downTo-1-Range in Zweierschritten for (i in 7 downTo 1 step 2) print("$i ") // 7 5 3 1
Funktionen höherer Ordnung Kotlin unterstützt die Verwendung von Funktionen höherer Ordnung sowie von Closures mithilfe von Funktionszeigern, anonymen Funktionen und Lambda-Ausdrücken. // Funktion, die eine andere Funktion entgegennimmt fun callWithInt(number: Int, fn: (Int) -> Int) { val result = fn(number) println(result) }
// Funktion, die eine andere Funktion zurückgibt fun makeAdder(a: Int): (Int) -> Int { fun add(b: Int) = a + b return ::add }
// Anders als in Java dürfen in Kotlin Closures auf Variablen auch schreibend zugreifen var number = 0 fun makeCounter(): () -> Int { fun counter() = ++number return ::counter }
fun double(x: Int) = x * 2
fun main() { // Aufruf mit Funktionszeiger callWithInt(42, ::double)
// Aufruf mit anonymer Funktion callWithInt(42, fun(x: Int) = x * 2)
// Aufruf mit Lambda-Ausdruck callWithInt(42, { x -> x * 2})
// Als letztes Argument dürfen Lambdas außerhalb der runden Klammern geschrieben werden. // Wenn die Funktion nur ein Argument erwartet, heißt dieses "it", falls nicht anders festgelegt. callWithInt(42) { it * 2 }
val add2 = makeAdder(2) println(add2(5)) // gibt 7 aus
val counter = makeCounter() println(counter()) // Gibt 1 aus println(counter()) // Gibt 2 aus } Funktionen höherer Ordnung werden auch in der Standardbibliothek verwendet, insbesondere bei Collections-Datentypen wie Listen, Maps oder Sets. val list = setOf(1, 2, 3, 4, 5)
println(list.map { it * 2 }) // [2, 4, 6, 8, 10] println(list.filter { it > 2 }) // [3, 4, 5] println(list.groupBy { it % 2 }) // {1=[1, 3, 5], 0=[2, 4]}
val cities = listOf("Berlin", "Hamburg", "München", "Köln", "Frankfurt")
// Die Anfangsbuchstaben der drei Städte mit den kürzesten Namen hintereinander val result = cities .sortedBy { it.length } .take(3) .map { it } .fold("") { acc, char -> acc + char }
println(result) // KBH
Null Safety Die falsche Verwendung von Null-Pointern, die zu sogenannten „Null Pointer Exceptions“ führen können, ist in vielen Programmiersprachen eine häufige Fehlerursache. Daher stellt Kotlin eine Reihe von Features zur Verfügung, die das Auftreten solcher Null Pointer Exceptions bereits zur Kompilierzeit verhindern sollen. So muss der Entwickler zum Beispiel beim Deklarieren einer Variable explizit angeben, ob diese den Wert null annehmen darf oder nicht. Variablen, die null sein können, werden „nullable“ (etwa: nullierbar) genannt.// Erstellt eine Variable vom Typ "Int" (darf nicht "null" sein) var a: Int = 123
// Erstellt eine Variable, die den Wert "null" annehmen darf. var b: Int? = 456
// Nicht erlaubt (Erzeugt einen Kompilierfehler) a = null
// Zugelassen b = null Wenn eine Variable, die null werden kann, verwendet wird, ohne sie vorher auf null geprüft zu haben, führt dies beim Kompilieren ebenfalls zu einem Fehler. fun nullSafety() { val test: String? = "Test"
// Kompilierfehler (könnte "Null Pointer Exception" verursachen) println(test.length)
// Erlaubt, da auf null abgeprüft wird. if (test != null) println(test.length)
// Auch erlaubt (zweite Bedingung wird nur überprüft, wenn die erste falsch ist) if (test == null || test.length == 0) println("Leerer String")
// Ebenfalls erlaubt if (test == null) return
println(test.length) } Kotlin bietet außerdem für einige typische Fälle besondere Syntax, um den benötigten Code zu verkürzen. val ort = kunde?.adresse?.ort val ortOderLeer = ort ?: ""
// Obiger Code ist gleichbedeutend mit:
val ort: String? if (kunde == null || kunde.adresse == null) ort = null else ort = kunde.adresse.ort
val ortOderLeer: String if (ort == null) ortOderLeer = "" else ortOderLeer = ort
Versionen Seit Kotlin 2.0.0 werden folgende Arten von Releases veröffentlicht:
Language Releases (2.x.0): Große Änderungen in der Programmiersprache, Tooling-Aktualisierungen. Werden alle 6 Monate veröffentlicht. Tooling Releases (2.x.20): Performance Verbesserungen, Fehlerbehebungen. Werden 3 Monate nach dem entsprechenden Language Release veröffentlicht. Bug Fix Releases (2.x.yz): Fehlerbehebungen für Tooling Releases. Kein Zeitplan für die Veröffentlichung.