Kotlin

Lesezeit: 10 Minuten

Kotlin ist eine kompilierte, statisch typisierte Programmiersprache, die prozedurale, objektorientierte, funktionale und aspektorientierte Programmierung vereint. Kotlin wird vorrangig in Bytecode für die JVM übersetzt und kann damit wie ein Java-Programm ausgeführt werden. Es ist jedoch auch möglich, Kotlin nativ zu kompilieren oder zu JavaScript zu transpilieren.

Das Projekt Kotlin wurde 2011 von dem vor allem durch seine Entwicklungsumgebung IntelliJ IDEA bekannten Softwareunternehmen JetBrains der Öffentlichkeit bekannt gemacht. Im Jahr 2016 erschien die Version 1.0. Der Name Kotlin wurde wegen der gleichnamigen Insel in der Nähe des in St. Petersburg ansässigen Entwicklerteams gewählt, angelehnt an Java, das kurioserweise aber eher nicht die gleichnamige Insel als Namensgeber hat.

Alleinstellungsmerkmale

Kotlin wird berechtigerweise gerne mit Java verglichen und hat sich dadurch nicht nur als eine führende Sprache im Android-Ökosystem entwickelt, sondern ist auch für viele Entwicklungsteams interessant, die lange Zeit mit Java entwickelt haben. Kotlin ist vollständig mit Java interoperabel, was eine schrittweise Migration einer Java-Anwendung zu Kotlin verhältnismäßig einfach macht. Innerhalb von IntelliJ IDEA kann Java-Code beim Einfügen in eine Kotlin-Quellcodedatei sogar on-the-fly in Kotlin-Code übersetzt werden.

Kotlin auf Java zu reduzieren wird der Sprache aber nicht gerecht. Kotlin/JS kann eine gute Alternative zu JavaScript oder TypeScript sein. Kotlin/Native wiederum kann eine Alternative zu Sprachen wie Go sein, die eine ausführbare Datei mit integrierter Laufzeitumgebung und automatischer Speicherbereinigung erzeugen. Wobei man klar sagen muss, dass Kotlin aktuell in Sachen Performance mit Go nicht mithalten kann.

Kotlin sticht für mich auch durch eine Vielzahl an Syntaxen (mit viel Zucker) hervor, darunter mit Konzepten wie Scope Functions und Extension Functions, die gegenüber Java lesbareren Code und weniger Boilerplate Code zur Folge haben können.

Einsatzbereiche

Kotlin ist seit 2019 die von Google empfohlene Sprache zur Entwicklung auf Android. Google gibt an, dass mehr als zwei Drittel der Top-1000-Android-Apps im Google Play Store in Kotlin implementiert sind. Viele Apps von Google selbst wie Maps und Drive sind in Kotlin geschrieben.

Das Spring-Framework unterstützt Kotlin seit 2017 offiziell. Allegro, Amazon, Atlassian, Basecamp, Duolingo, Evernote, Google, Gradle, Netflix, Pinterest, Shazam, Uber und Zalando setzen unter anderem Kotlin ein.

Pros

Kotlin ist vollständig interoperabel mit Java und hat dadurch Zugriff auf ein enormes Ökosystem. Als offiziell von Google bevorzugte Sprache für Android und mit JetBrains als renommierten Entwickler der Sprache ist Kotlin meiner Meinung trotz seines geringen Alters für die Zukunft gut aufgestellt. Dass bei Kotlin Sprache und IDE aus einer Hand kommen, sehe ich als großes Plus, vor allem da IntelliJ IDEA meiner Auffassung nach nicht nur sehr verbreitet, sondern bei Java-Entwicklern auch extrem beliebt (bis hin zu alternativlos) ist.

Kotlin kann aber nicht nur auf Java-, sondern auch auf JavaScript-Code zugreifen. Dieser kann eingebettet oder auch extern vorliegen. So kann z.B. auch aus Kotlin heraus auf NPM-Bibliotheken zugegriffen werden. Die JavaScript-Interoperabilität ist allerdings zum Teil noch experimentell.

Kotlin ist sehr auf Fehlervermeidung bedacht. Typen sind standardmäßig nicht nullable, um NullPointer-Fehler zu vermeiden – als weiterführende Lektüre ist am Ende des Beitrags der Artikel „Null Pointer References: The Billion Dollar Mistake“ verlinkt. Jeder Typ kann durch ein angefügtes Fragezeichen ? als nullable deklariert werden: var foo: String ist nicht nullable, var foo: String? hingegen schon.

Klassen sind standardmäßig final und müssen mit dem Schlüsselwort open versehen werden, um abgeleitet werden zu können. Variable Typen und Konstanten werden mit den Schlüsselwörtern var und val deklariert, statt dass es wie in Java eines weiteren Modifikators final bedarf. Mit dem Schlüsselwort sealed können Klassen auch eingeschränkt vererbbar gestaltet werden. Listen können z.B. über die eingebaute Funktion listOf() erzeugt werden und sind in dem Fall immutable. Wird eine Liste gewünscht, in der Einträge hinzugefügt und entfernt werden können, so wird dies über den Funktionsnamen explizit gemacht: mutableListOf()

Kotlin unterstützt Higher-Order Functions und Lambdas. Auch Monaden sind Teil der Sprache. runCatchable etwa kapselt eine Aktion in einem Result-Objekt, so dass auf try/catch verzichtet werden kann.

Kotlin bietet den auch aus JavaScript bekannten Null Coalescing Operator und den Elvis-Operator, der eine Alternative in dem Fall anbietet, dass ein Wert null ist:

// ?. ruft close() nur dann auf, wenn connection nicht null ist
connection?.close()

// ?: gibt den Wert von getString(1) zurück
// oder einen Leerstring falls der Wert null sein sollte
var name = result.getString(1) ?: "" 

Unter dem Schlüsselwort data bietet Kotlin ein Gegenstück zu den in Java 14 eingeführten Records: Klassen, die implizit oft verwendete Funktionen wie toString(), equals() und hashCode() implementieren.

Kotlin bietet in der Standardbibliothek die Klassen Pair und Triple, die auch verwendet werden können, um über eine Funktion mehrere Werte zurückzugeben. Alternativ lassen sich dafür auch gut Listen verwenden, da es für sie gegenüber Java verkürzte Zugriffsmöglichkeiten wie z.B. list[0] für das erste Element gibt.

Über das Schlüsselwort infix können Funktionen ohne Punkt und runde Klammern aufgerufen werden, was sinnvoll im Rahmen von domänenspezifischen Sprachen und auch einigen Randfällen wie Maps ist. Da es sich bei to() um eine infix-Funktion handelt, kann eine Map wie folgt initialisiert werden:

var myMap = map(
    1 to "foo",
    2 to "bar",
    3 to "foobar"
)

Kotlin unterstützt Raw Strings (multi line strings) und String Interpolation, also das Einbinden von Variablen und beliebigen Ausdrücken in Strings. Semikolons sind in Kotlin optional. Typen können abgeleitet werden (type inference). Kotlin hat einen Spread Operator, der wie in Python durch einen einer Liste vorangestelltes Asterisk abgebildet wird.

Zwei meiner persönlichen Highlights in Kotlin sind Scope Functions und Extension Functions. Mit Scope Functions können beliebige Code-Blöcke im Kontext eines Objektes ausgeführt werden. Damit lässt sich z.B. vermeiden, dass man den Rückgabewert einer Funktion mit Seiteneffekten in einer Variable „parken“ muss, weil man mehrfach darauf zurückgreift. Extension Functions ermöglichen es, bestehende Klassen um neue Funktionen zu erweitern. Möchte man in Java den Funktionsumfang einer Klasse wie String erweitern, so führt dies meist zu neuen „Util“-Klassen. Der nachfolgende Code verdeutlicht den Einsatz von Scope Functions und Extension Functions. Hier zunächst der Original-Code in Java:

try (var statement = connection.createStatement()) {
    final var result = statement.executeQuery("SOME SQL");
    return result.next() 
        ? result.getBigDecimal(1)
            .setScale(2, RoundingMode.HALF_UP) 
        : BigDecimal.ZERO;
}

Hier der gleiche Code in Kotlin:

return connection.query("SOME SQL").let {
    if (it.next()) it.bd(1).normalize() else 0.toBigDecimal()
}

Dieser deutlich kürzere Code wird unter dem Einsatz von Extension Functions ermöglicht, die an anderer Stelle wie folgt definiert sein könnten:

fun Connection.query(qry: String): ResultSet = this.createStatement().executeQuery(qry)
fun ResultSet.bd(i: Int): BigDecimal = this.getBigDecimal(i)
fun BigDecimal.normalize(): BigDecimal = this.setScale(2, RoundingMode.HALF_UP)

Der Code zeigt Folgendes auf:

  • Die Klassen Connection und ResultSet aus dem Package java.sql sowie die Klasse BigDecimal werden um „Abkürzungen“ erweitert, um lesbareren Code schreiben zu können. In Java würde man solche Abkürzungen üblicherweise in eine Hilfsklasse oder statische Methode auslagern, da die Möglichkeit, die Originalklasse ohne Ableitung zu erweitern, nicht gegeben ist.
  • Im Java-Code wird eine lokale Variable result deklariert, da auf das Ergebnis zweimal zurückgegriffen wird.
  • Im Kotlin-Code kann die Variable result durch die Verwendung der Scope Function let() umgangen werden. Diese Scope Function erlaubt den Zugriff auf den Rückgabewert via it und gibt den letzten Ausdruck des Blocks automatisch zurück.
  • Wie man außerdem sehen kann, wird der Ternary Operator in Kotlin ähnlich wie auch in Python via if/else abgebildet und Werte wie 0 sind vollwertige Objekte, es können an ihnen also auch Methoden wie in diesem Fall toBigDecimal() aufgerufen werden.

Cons

Kotlin hat zum jetzigen Zeitpunkt über 70 Schlüsselwörter. Zwar ist Kotlin keine schwierige Sprache, bietet aber Unmengen an Möglichkeiten. Das kann dazu führen, dass Entwickler überfordert sind und Bad Practices entstehen. Auch kann es sein, dass Features kaum eingesetzt werden und man sie im Sinne des Principles of Least Surprise eher vermeidet. Ein Beispiel dafür in Java sind meiner Meinung nach Init-Blöcke, die ich so selten sehe, dass ich mich frage, ob die meisten Entwickler überhaupt wissen, dass es sie gibt und wann man sie einsetzen sollte (und wann nicht).

Funktionen in Kotlin sind standardmäßig öffentlich. Dies ist eine Designentscheidung, die man durchaus kritisch sehen kann. Denn sie kann dazu verleiten, Kapselung nicht angemessen einzusetzen und Interna einer Klasse preiszugeben, weil eine Schreibweise fun foo() eben kürzer und lesbarer ist als private fun foo().

Im Vergleich zu Sprachen wie Java und Python ist Kotlin verhältnismäßig jung. Dies macht es schwieriger, Kotlin als Entwicklungssprache im Unternehmen durchzusetzen. Gleichzeitig ist es schwieriger erfahrene Kotlin-Programmierer zu finden, als beispielsweise Java-Entwickler. Dem möchte ich allerdings hinzufügen, dass ein erfahrener Java-Entwickler Kotlin mit geringem Aufwand lernen kann.

Datenblatt

NameKotlin
Webseitehttps://kotlinlang.org/
Erscheinungsjahr2011
Aktuellste Version (Stand 13. März 2022)Version 1.6.10 vom 14. Dezember 2021
Typisierungstatisch
Paradigmenimperativ
prozedural
objektorientiert
funktional
aspektorientiert
ProsCons
Interoperabilität mit Javaüber 70 Schlüsselwörter
riesiges Ökosystem dank Java (wenn man Kotlin in Bytecode übersetzt)relativ junge Sprache
Ausführung von JavaScript (zum Teil noch experimentell)Funktionen sind per default öffentlich
native Kompilierung möglich (inklusive automatischer Speicherbereinigung)
eine Vielzahl an kleveren Syntaxen um konzisen Code zu schreiben und Boilerplate Code zu vermeiden
viele Features zur Fehlervermeidung
gute Eignung für DSLs (domänenspezifische Sprachen)
Sprache und Entwicklungsumgebung aus einer Hand
von Google empfohlene Sprache unter Android

virtuallet

virtuallet ist ein kleines Programm von mir, welches ich in diversen Programmiersprachen implementiert habe. Hier geht es direkt zum Kotlin-Code von virtuallet auf GitLab. Hier gibt es weitere Infos zu virtuallet.

- Android wird Kotlin-First
- The Billion Dollar Mistake