Hauptsächlich wurde die Sprache von den damals in Sankt Petersburg ansässigen JetBrains-Programmierern entwickelt.[7][8] Daher stammt auch der Name: Kotlin ist eine Insel vor St. Petersburg.[9]
Nach einem Jahr Entwicklung stellte JetBrains im Juli 2011 das Projekt „Kotlin“ der Öffentlichkeit als neue Sprache für die JVM vor.[10][11] Im Februar 2012 veröffentlichte JetBrains den Quellcode unter einer Apache-2-Lizenz.[12] Am 15. Februar 2016 wurde die Version 1.0 von Kotlin veröffentlicht.[13] Diese Version wird als erstes offizielles Stable-Release betrachtet.
Der leitende Entwickler Dmitry Jemerow 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.[11] Daher war eines der erklärten Ziele für Kotlin die hohe Kompiliergeschwindigkeit, wie man sie von Java her kenne.
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.[21] Daneben existieren auch native Test-Frameworks für Kotlin wie z. B. kotlin-test.[22]
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.[23] 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.[24] Als Einstiegspunkt dient wie bei C u. ä. eine Main-Funktion.
Hallo Welt
Ein Programm, das die Zeichenkette „Hallo Welt“ ausgibt.
funmain(){// Einsprungpunkt (Main-Funktion)println("Hallo Welt!")// Gib den String 'Hallo Welt!' aus}
Funktionen
// Definition einer Funktion "funktionsBeispiel"funfunktionsBeispiel(){// ...}// Funktion mit zwei Argumenten und einem Rückgabewertfunadd(x:Int,y:Int):Int{returnx+y}// Besteht eine Funktion aus nur einem Ausdruck, dürfen die geschweiften Klammern, der Rückgabetyp und das "return" weggelassen werden.funadd2(x:Int,y:Int)=x+y// Einsprungpunkt (Main-Funktion)funmain(args:Array<String>){// Definition einer verschachtelten Funktion, die nur in main aufgerufen werden kann.funtest(){println("Hello World!")}// Aufrufen der Funktiontest()}
Klassen und Objekte
// Definition einer BeispielklasseclassKlassenBeispiel(// Argumentex:Float,vartext:String){// Attribute werden wie eine Variable in der Klasse definiertvalzahl=x.toInt()// init-Blockinit{println("Klasse wurde initialisiert mit Float $x")}// Interne MethodefuntextUmdrehen(){text=text.reversed()}// Methode mit RückgabewertfunersteXTextBuchstaben():String{returntext.slice(0..<zahl)}}funmain(){valobjekt=KlassenBeispiel(4f,"Hallo Wiki")// -> Klasse wurde initialisiert mit Float 4.0println("Zahl ist ${objekt.zahl}, Text ist ${objekt.text}")// -> Zahl ist 4, Text ist Hallo Wikiobjekt.textUmdrehen()println(objekt.text)// -> ikiW ollaHprintln(objekt.ersteXTextBuchstaben())// -> ikiW}
// Weist der schreibgeschützten lokalen Variable 'x' die Tastatureingabe (standard input stream) als Integer-Wert zu.valx=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")elseif(x<0)print("negativ")elseprint("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.valx=readLine()!!.toInt()when(x){1->print("x == 1")2->print("x == 2")3,4->print("x == 3 oder x == 4")in5..7->print("x zwischen 5 und 7")else->print("x ist kleiner als 1 oder größer als 7.")}
Repeat-Anweisung
// Wiederholt die Funktionsanweisung 2xrepeat(2){println("Hello Wiki")}// Hello Wiki// Hello Wiki
For-Schleife
// Iteriert i innerhalb der 7-downTo-1-Range in Zweierschrittenfor(iin7downTo1step2)print("$i ")// 7 5 3 1
// Funktion, die eine andere Funktion entgegennimmtfuncallWithInt(number:Int,fn:(Int)->Int){valresult=fn(number)println(result)}// Funktion, die eine andere Funktion zurückgibtfunmakeAdder(a:Int):(Int)->Int{funadd(b:Int)=a+breturn::add}// Anders als in Java dürfen in Kotlin Closures auf Variablen auch schreibend zugreifenvarnumber=0funmakeCounter():()->Int{funcounter()=++numberreturn::counter}fundouble(x:Int)=x*2funmain(){// Aufruf mit FunktionszeigercallWithInt(42,::double)// Aufruf mit anonymer FunktioncallWithInt(42,fun(x:Int)=x*2)// Aufruf mit Lambda-AusdruckcallWithInt(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}valadd2=makeAdder(2)println(add2(5))// gibt 7 ausvalcounter=makeCounter()println(counter())// Gibt 1 ausprintln(counter())// Gibt 2 aus}
Funktionen höherer Ordnung werden auch in der Standardbibliothek verwendet, insbesondere bei Collections-Datentypen wie Listen, Maps oder Sets.
vallist=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]}valcities=listOf("Berlin","Hamburg","München","Köln","Frankfurt")// Die Anfangsbuchstaben der drei Städte mit den kürzesten Namen hintereinandervalresult=cities.sortedBy{it.length}.take(3).map{it[0]}.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)vara:Int=123// Erstellt eine Variable, die den Wert "null" annehmen darf.varb:Int?=456// Nicht erlaubt (Erzeugt einen Kompilierfehler)a=null// Zugelassenb=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.
funnullSafety(){valtest: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 erlaubtif(test==null)returnprintln(test.length)}
Kotlin bietet außerdem für einige typische Fälle besondere Syntax, um den benötigten Code zu verkürzen.
valort=kunde?.adresse?.ortvalortOderLeer=ort?:""// Obiger Code ist gleichbedeutend mit:valort:String?if(kunde==null||kunde.adresse==null)ort=nullelseort=kunde.adresse.ortvalortOderLeer:Stringif(ort==null)ortOderLeer=""elseortOderLeer=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.[25]
Version
Datum
Wichtige Änderungen
M1
12. April 2012
Erster Milestone Release. Erster eigenständig lauffähiger Compiler. Erste Version der Kotlin-Standardbibliothek.[26]
M2
11. Juni 2012
Einführung von Zugriffsmodifikatoren. Android Support wurde eingeführt.[27][28]
M3
20. September 2012
Mehrfachzuweisungen und Dataclasses wurden eingeführt. Erste Version von Kotlin Collections. Externe Annotationen und lokale Funktionen und Klassen werden ermöglicht.[29]
M4
11. Dezember 2012
JDK7-Kompatibilität wurde hinzugefügt. Deprecation Support über neue Annotation.[30]
M5
04. Februar 2013
Package Classes als Ersatz für Namespace-Klassen. Innere Klassen sind nun möglich. Default-Konstruktoren werden nun automatisch generiert.[31]
M6
12. August 2013
Annotationen können nur Argumente vom Typ Enum verwenden. Erste Version auf Maven Central. Android-Studio-Support.[32]
M7
20. März 2014
Inline Support für Lambda-Funktionen während der Kompilierzeit. toString(), equals() und hashCode() müssen nun explizit überschrieben werden. Throws Annotation für das Werfen von Exceptions wurde hinzugefügt. Streams werden nun unterstützt.[33]
M8
02. Juli 2014
Reflections erlauben nun auch den Zugriff auf Felder. transient, synchronized und strictfp keywords wurden hinzugefügt.[34]
M9
15. Oktober 2014
Inkrementelles Kompilieren des Quellcodes wird ermöglicht. Verbesserter Support für gemeinsamen Einsatz von Java und Kotlin unter anderem durch Plattformtypen.[35][36]
M10
17. Dezember 2014
Der reified-Parameter kann auch in Inline-Funktionen verwendet werden. Über die Java Native API können auch native Funktionen deklariert werden.[37]
M11
19. März 2015
Eine Klasse kann nun über mehrere Konstruktoren verfügen. Der Initialisierungsblock wird über das Keyword init markiert. Companion-Objekte können direkt über die Containerklasse angesprochen werden. Eigene Reflection API unabhängig von der JVM.[38]
M12
29. Mai 2015
Enums und Annotationen haben eine neue Syntax bekommen. Smart Casts wurden verbessert. Funktionstypen und erweiterte Funktionstypen können nun gegeneinander ausgetauscht werden.[39]
M13
16. September 2015
Über lateinit können nun auch Felder, die keine Null-Werte beinhalten dürfen, über Dependency Injection initialisiert werden. Sealed-Klassen ermöglichen Algebraischer Datentypen. Annotationen für Annotationen wurden eingeführt. Modifikatoren und Annotationen wurden syntaktisch getrennt. Erweiterung der Reflection API.[40]
M14
01. Oktober 2015
Annotationen können zur file-Klasse hinzugefügt werden. Reorganisation von Hilfsklassen in einzelne Klasse für jeden Datentyp.[41]
1.0
15. Februar 2016
Erster offizieller Release. Zukünftige Versionen sollen abwärtskompatibel bleiben. Hierzu werden in früheren Versionen als deprecated markierte Features als Error markiert.[42]
1.1
01. März 2017
Koroutinen erlauben eine einfache Programmierung von asynchronem Code. Offizieller Release für das Kotlin JavaScript Target, um Kotlin-Code direkt in JavaScript-Code zu kompilieren.[43]
1.2
28. November 2017
Einführung von Multiplattform-Projekten, um Code zwischen den verschiedenen Ebenen eines Projektes mehrfach zu verwenden. Effizientere Kompilierung.[44]
1.3
29. Oktober 2018
Beta zu Kotlin Native. Code kann direkt in native Binary-Dateien kompiliert werden.[45]
1.4.0
17. August 2020
Verbesserte Performance und Stabilität. Single-Abstract-Method-Konvertierung kann nun auch auf Kotlin-Code direkt angewendet werden.[46]
1.4.20
23. November 2020
1.4.30
03. Februar 2021
1.5.0
5. Mai 2021
Der JVM IR Compiler ist nun der Standardcompiler für Kotlin. Sealed Interfaces und Inline-Klassen wurden hinzugefügt.[47]
1.5.20
24. Juni 2021
1.5.30
24. August 2021
1.6.0
16. November 2021
Einführung von sealed-when-Ausdrücken. Neuer Kotlin-Native-Speichermanager.[48]
1.6.20
04. April 2022
1.7.0
09. Juni 2022
Einführung des Kotlin K2 Compilers. Inkrementelle Kompilierung unterstützt nun auch nicht Kotlin-Komponenten in einem Gradle-Bau.[49]
1.7.20
29. September 2022
1.8.0
28. Dezember 2022
Performance-Verbesserung für Reflection. Bessere Interoperabilität mit Objective-C/Swift[50]
1.8.20
25. April 2023
1.9.0
06. Juli 2023
Feature Release mit Kotlin K2 Compiler Updates, einer neuen Funktion für Enum Klassenwerte, einem neuen Operator für offene Bereiche, einer Vorschau auf den Gradle Configuration Cache in Kotlin Multiplatform. Änderungen am Android Target Support in Kotlin Multiplatform und einer Vorschau auf einen Custom Memory Allocator in Kotlin/Native.[51]
1.9.20
01. November 2023
2.0.0
21. Mai 2024
Language Release mit dem Stable Kotlin K2 Compiler.[52]
2.0.20
22. August 2024
2.1.0
27. November 2024
Language Release mit der Einführung neuer Language Features[53]
Rezeption
Google hat Kotlin auf der Entwicklerkonferenz I/O 2019 zur bevorzugten Programmiersprache für Android erklärt.[54]
Meta Platforms nutzt nach eigenen Angaben in seiner Android-Codebase im Oktober 2022 mehr als 10 Millionen Zeilen Code, der in Kotlin geschrieben ist.[55]
In der Ausgabe Januar 2012 des Dr. Dobb’s Journal wurde die Programmiersprache zur Sprache des Monats (language of the month) erklärt.[56]
Der Kotlin-Website zufolge setzen kleine wie große Projekte die Sprache ein:
Pinterest nutzen monatlich 150 Millionen Anwender.
Stephen Samuel, Stefan Bocutiu: Learn Kotlin Programming: A comprehensive guide to OOP, functions, concurrency, and coroutines in Kotlin 1.3, 2nd Edition. Packt Publishing, 2019, ISBN 978-1-78980-874-2 (google.com).