Blog

Kotlin lernen - Eine schöne Sprache für die JVM

Dennis Vriend

Aktualisiert Oktober 21, 2025
12 Minuten

Kotlin ist eine statisch typisierte Programmiersprache, die von Jetbrains, dem Erfinder der IntelliJ IDE-Plattform, entwickelt wurde. Die Sprache wurde 2016 zum ersten Mal veröffentlicht und hat seither viel Zuspruch erhalten. Kotlin wird als Backend-Sprache, als Front-End-Sprache und auf der mobilen Plattform, insbesondere Android, eingesetzt. Kotlin entwickelt sich in einem enormen Tempo weiter und wird auf allen Plattformen verfügbar sein, von JVM über JavaScript bis hin zu nativen Sprachen. Zeit, uns Kotlin beizubringen!

Was ist Kotlin

Kotlin ist eine generische Programmiersprache für mehrere Plattformen und Paradigmen, die mit verschiedenen Compilern geliefert wird. Mit den Kotlin-Compilern kann Code zu JVM-Bytecode kompiliert werden, der auf der Java Virtual Machine ausgeführt werden kann. Es gibt auch einen JavaScript-Compiler, so dass der Code in Browsern oder der NodeJS-Laufzeitumgebung ausgeführt werden kann. Es gibt auch einen LLVM-Compiler, mit dem Kotlin zu einer statischen Binärdatei kompiliert werden kann.
Die Syntax von Kotlin ist stark von Scala inspiriert, um die Sprache sehr prägnant zu machen, aber es fehlen Funktionen, die Kotlin sehr leicht erlernbar machen. Durch den Verzicht auf fortgeschrittene Sprachfunktionen wird die Sprache pragmatischer und für die breite Öffentlichkeit nutzbar. Kotlin wird allgemein als eine freundliche Sprache mit gerade genug Abstraktionen angesehen, die Kotlin für den täglichen Gebrauch geeignet machen.
Die Ausgewogenheit von gerade genug Typinferenz, funktionalen Abstraktionen, Multi-Plattform-Integration und Geschwindigkeit ist der Grund, warum die Sprache so beliebt ist. Die Syntax ist zwar nicht mit Java kompatibel, aber die JVM-Implementierung der Kotlin-Standardbibliothek ist so konzipiert, dass sie mit Java-Code und -Bibliotheken interoperabel ist. Kotlin verwendet die Typinferenz, um den Umfang der Sprache zu reduzieren, und unterstützt eine ganze Reihe funktionaler Sprachfunktionen und fortschrittlicher Primitive für die Gleichzeitigkeit.

Einige Annahmen

Bevor wir fortfahren, gehe ich davon aus, dass Sie einen Mac haben, mit Homebrew eingerichtet sind und Erfahrung mit JVM-Sprachen wie Java oder Scala haben. Die meisten der Beispiele werden mit der REPL ausgeführt.

Kotlin installieren

Auf einem Mac können Sie Kotlin installieren, indem Sie Folgendes eingeben.

$ brew install kotlin

$ kotlin -version
Kotlin version 1.3.10-release-253 (JRE 1.8.0_172-b11)

$ kotlinc -version
info: kotlinc-jvm 1.3.10 (JRE 1.8.0_172-b11)

$ kotlinc-jvm -version
info: kotlinc-jvm 1.3.10 (JRE 1.8.0_172-b11)

$ kotlinc-js -version
info: kotlinc-js 1.3.10 (JRE 1.8.0_172-b11)

REPL

Kotlin verfügt über eine Read Evaluate Print Loop (REPL):

$ kotlinc
Welcome to Kotlin version 1.3.10 (JRE 1.8.0_172-b11)
Type :help for help, :quit for quit
>>> :help
Available commands:
:help                   show this help
:quit                   exit the interpreter
:dump bytecode          dump classes to terminal
:load <file>            load script from specified file

>>> listOf(1, 2, 3).map { it + 2 }.map { it * 2 }.filter { it > 6 }.sum()
18

>>> :quit

Kotlin lernen

Es gibt eine Menge Ressourcen, um Kotlin zu lernen. Kotlin bietet eine Vielzahl von Ressourcen, um Kotlin zu lernen. Die Kotlin-Dokumentation ist großartig! Da Jetbrains Kotlin unterstützt, gibt es auch ein Kotlin Educational Plugin, mit dem Sie Kotlin in die Praxis umsetzen können. Es gibt viele Bücher zum Erlernen von Kotlin. Der JetbrainsTV YouTube-Kanal enthält eine Menge Videos über Kotlin. Die Videos der KotlinConf 2018 sind auf demselben Kanal verfügbar. Neben all den Online-Lernressourcen bietet Jetbrains auch einen Kurs auf Coursera an.

Gradle Build Tool

Kotlin kann mit jedem Tool erstellt werden, da die Compiler als Kommandozeilen-Tools verfügbar sind, aber der bevorzugte Weg zur Erstellung von Kotlin-Programmen ist Gradle. Wenn Sie wissen möchten, wie Sie Gradle verwenden, lesen Sie meinen früheren Blog Learning Gradle - An Open Source Build Automation Tool.

Datentypen

Kotlin unterstützt die folgenden grundlegenden Datentypen:

val a: Double = 2.0
val b: Float = 2.0f
val c: Long = 1L
val d: Int = 1
val e: Short = 1
val f: Byte = 1
val g: Int = 0x0F
val h: Int = 0b00001011
val i: Char = 'a'
val j: Boolean = true
val k: UInt = 1u
val l: UShort = 1u
val m: UInt = 1u
val n: ULong = 1u
// octal is not supported
println("$a $b $c $d $e $f $g $h $i $j $k $l $m $n")

Streicher

Kotlin hat die folgenden String-Darstellungen:

val a: String = "foo"
val b: String = "bar" + "baz"
val c: String = "Hello Worldn"
val d: String = """Multi
                Line
                String"""
val e: String = """
    |Lorem ipsum dolor amet tousled coloring book pickled pug church-key, disrupt PBR&B schlitz celiac.
    |Taxidermy pork belly celiac, shabby chic drinking vinegar seitan etsy retro banjo listicle ramps.
    |Paleo blog shoreditch, taxidermy gastropub bespoke yuccie hexagon hammock sartorial ethical everyday
    |carry typewriter messenger bag cliche.
""".trimMargin()

String-Interpolation:

val a = 1
val b = 2
val c = a + b
val d = "$a + $b = $c"

Funktionen

Kotlin unterstützt Funktionen:

fun double(x: Int): Int {
    return x + 1
}
val x = double(1)

Lambdas und anonyme Funktionen:
Ein Lambda-Ausdruck ist immer von geschweiften Klammern umgeben. In Kotlin gibt es die Konvention, dass, wenn der letzte Parameter einer Funktion eine Funktion akzeptiert, ein Lambda-Ausdruck, der als entsprechendes Argument übergeben wird, außerhalb der Klammern platziert werden kann. Wenn eine Funktion ein einziges Argument hat, ist der Funktionsparameter unter dem Namen verfügbar. Der Typ von it wird vom Compiler hergeleitet.

fun g(x: Int, f: (Int) -> Int): (Int) -> Int {
    // return a lambda
    return { y -> f(x) + y }
}

fun h(x: Int, f: (Int) -> Int): (Int) -> Int {
    // return an anonymous function
    return fun (y: Int): Int { return f(x) + y }
}

    val a = g(2) { x -> x + 5}
    val a = g(2) { it + 5} // single argument
    val b = a(10)

    val c = h(2) { x -> x + 5}
    val c = h(2) { it + 5} // single argument
    val d = c(10)
    println("$b $d")

Paket und Importe

Wie Java verwendet Kotlin Pakete und Importe, um Funktionen zu partitionieren und zu gruppieren und Namenskollisionen zu vermeiden. Eine Kotlin-Quelldatei beginnt mit einer package Deklaration, gefolgt von einer oder mehreren Import-Anweisungen.

package baz.bar

import foo.Bar
import foo.Bar as fBar
import foo.*

fun foo() {}
class Bar

Jede Kotlin-Datei importiert standardmäßig die folgenden Pakete:

  • kotlin.*
  • kotlin.annotation.*
  • kotlin.collections.*
  • kotlin.comparisons.*
  • kotlin.io.*
  • kotlin.ranges.*
  • kotlin.sequences.*
  • kotlin.text.*
  • java.lang.*
  • kotlin.jvm.*

Mit dem Schlüsselwort import können Sie Klassen, Top-Level-Funktionen und Eigenschaften sowie Enum-Konstanten importieren.

Klassen

Kotlin unterstützt die Definition von Klassen:

class Person(val name: String, val age: Int) {
    fun walk(): Unit {
        println("$name is walking")
    }
}

val p = Person("Dennis", 42)
p.walk()

Daten-Klassen

Kotlin unterstützt die Definition von Datenklassen, d.h. Klassen, die nur dazu da sind, Daten zu speichern. Das generische Konzept von Datenklassen wird als 'Datensätze' bezeichnet. Der Compiler erstellt automatisch ein 'equals()/hashCode()-Paar', eine 'toString()', 'componentN()' Funktionen, die den Eigenschaften in der Reihenfolge ihrer Deklaration entsprechen und eine 'copy()' Funktion.

data class Person(val name: String, val age: Int)

val dennis = Person("Dennis", 42)
val (name, age) = dennis
println("$name $age $dennis")

Kontrollfluss

Kotlin bietet Kontrollflüsse, die Ausdrücke sind, d.h. sie geben einen Wert zurück.

val x = 2
val y = if (x > 1) x else 1
println(y)

Kotlin bietet When-Ausdrücke. Für Entwickler, die von Scala kommen, ist es kein Mustervergleich. Es gibt keine Dekomposition, d.h. Sie können keine Datenklassen dekomponieren.

val x = 2
val y = when {
    x > 1 -> x
    else -> 1
}
println(y)

Fehlerbehandlung

Für die Behandlung von Fehlern verwendet Kotlin die Syntax try-catch-finally. Kotin hat keine geprüften Ausnahmen, was großartig ist!

val x: Int = try {
    1/0
} catch (e: ArithmeticException) {
    println(e)
    0
} finally {
    0
}
println(x)

Null Sicherheit

Kotlin eliminiert Null-Referenzen mit Hilfe des elvis-Operators.
Kotlin fügt die folgenden Operatoren hinzu:

  • ?.Aufruf: Führt einen sicheren Aufruf aus (ruft eine Methode auf oder greift auf eine Eigenschaft zu, wenn der Empfänger nicht leer ist).
  • ?:elvis: nimmt den rechten Wert, wenn der linke Wert Null ist (der elvis-Operator)
val x: String? = null // define a nullable type
val y = if (x != null) x.length else -1
val z = x?.length ?: -1
println("$y $z")

Sammlungen

Kotlin bietet List, Set und Map.

val xs: List<int> = listOf(1, 2, 3).map { it + 2}
println(xs)
xs.forEach { println(it) }
val ys: List<int> = setOf(1, 1, 2, 2, 3, 3).map { it + 2}
println(ys)
ys.forEach { println(it) }
val zs: List<int> = xs.flatMap { x -> ys.map { it + x }}
println(zs)
zs.forEach { println(it) }
val kv: Map<string, String> = hashMapOf("name" to "Dennis", "age" to 42).mapValues { it.toString() }
kv.forEach { k, v -> println("k=$k, v=${v.javaClass}")}

Reichweite

Kotlin bietet Bereiche:

for (i in 1..10 step 2) println(i)
for (i in 10 downTo 1 step 2) println(i)
for (i in (1..10).reversed()) println(i)
for (i in 1.rangeTo(10)) println(i)
for (i in (1..10).map { it + 1 }.filter {it % 3 == 0}) println(i)

Erweiterungsmethoden

Erweiterungsmethoden ermöglichen die Erweiterung bestehender Klassen um neue Funktionen, ohne dass Sie von der Klasse erben oder eine Art von Entwurfsmuster wie Decorator verwenden müssen. Erstellen Sie eine Funktion mit dem Namen des Typs, wie Int, und geben Sie den Namen der neuen Funktion ein. Der Wert des Typs ist über die Referenz in der Funktion verfügbar. Um eine generische Erweiterungsmethode zu erstellen, verwenden Sie einen generischen Typ T und fügen die neue Funktion hinzu.

fun Int.sayMyName(): String {
    return "Dennis"
}

fun Int.sayMyNameAndAge(): String {
    return "Dennis $this"
}

fun Int.sayMyNameAndAdd(x: Int): String {
    return "Dennis ${this + x}"
}

fun <t : Any> T.whoAmI(): String {
    return "Dennis and I am ${this.javaClass}"
}

println(42.sayMyName())
Dennis
println(42.sayMyNameAndAge())
Dennis 42
println(42.sayMyNameAndAdd(10))
Dennis 52
println(listOf(1, 2, 3).whoAmI())
Dennis and I am class java.util.Arrays$ArrayList

Funktionale Programmierung

Funktionale Datenstrukturen, Muster und Typklassen können der Standardbibliothek von Kotlin mit Hilfe der Arrow-Bibliothek hinzugefügt werden. Arrow ist quelloffen und auf github
verfügbar. Fügen Sie Folgendes zu build.gradle.kts hinzu:

dependencies {
    // Use the Kotlin JDK 8 standard library
    implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")

    // add arrow
    val arrow_version = "0.8.1"
    compile("io.arrow-kt:arrow-core:$arrow_version")
    compile("io.arrow-kt:arrow-syntax:$arrow_version")
    compile("io.arrow-kt:arrow-typeclasses:$arrow_version")
    compile("io.arrow-kt:arrow-data:$arrow_version")
    compile("io.arrow-kt:arrow-instances-core:$arrow_version")
    compile("io.arrow-kt:arrow-instances-data:$arrow_version")
    kapt("io.arrow-kt:arrow-annotations-processor:$arrow_version")

    // Use the Kotlin test library
    testImplementation("org.jetbrains.kotlin:kotlin-test")

    // Use the Kotlin JUnit integration
    testImplementation("org.jetbrains.kotlin:kotlin-test-junit")
}

Verwenden Sie die funktionalen Datenstrukturen:

import arrow.core.Try
import arrow.instances.list.foldable.fold
import arrow.instances.monoid

val xs = listOf(1, 2, 3)
val x = xs.fold(Int.monoid())
println(x)

val y = Try { 1/0 }
val z: Int = y.fold({-1}){it}
println(z)

Gleichzeitigkeit

Coroutines sind eine Kotlin-Funktion, die asynchrone Rückrufe für langlaufende Aufgaben, wie z.B. Datenbank- oder Netzwerkzugriffe, in sequenziellen Code umwandelt. Für eine gute Einführung in Coroutines empfehle ich Ihnen Introduction to Coroutines von Roman Elizarov

dependencies {
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.0.1")
}

Beispiel: Hallo Welt

import kotlinx.coroutines.*

fun main(args: Array<string>) {
    GlobalScope.launch {
        // launch new coroutine in background and continue
        delay(1000L) // non-blocking delay for 1 second (default time unit is ms)
        println("World!") // print after delay
    }
    println("Hello,") // main thread continues while coroutine is delayed
    Thread.sleep(2000L) // block main thread for 2 seconds to keep JVM alive
}

Beispiel: Starten von 10.000 Coroutines. Die Anwendung läuft 5 Sekunden lang und alle Coroutines werden beendet.

import kotlinx.coroutines.*

suspend fun main(args: Array<string>) {
    val jobs = List(10000) {
        GlobalScope.launch {
            delay(5000)
            print(".")
        }
    }
    jobs.forEach { it.join() }
}

Zufallszahlengenerator

Im Folgenden werden Zufallszahlen generiert:

// generate a random number
for (x in 1..10) println((1..10).random())

// generate the same random number sequence every time
import kotlin.random.Random
val rnd = Random(1)
for (x in 1..10) println(rnd.nextInt(10))

UUID

Die JDK-Standardbibliothek kann eine UUID erzeugen.

import java.util.UUID

val uuid = UUID.randomUUID()

Dateien schreiben

Kotlin bietet Erweiterungsmethoden für java.io.File, um Dateien zu schreiben:

java.io.File("/tmp/test.json").writeText("""{"message": "Hello World!"}""")

Dateien lesen

Kotlin bietet Erweiterungsmethoden für java.io.File, um Dateien zu lesen:

val text = java.io.File("/tmp/test.json").readText()
println(text)

JSON-Kodierung

Moshi ist eine JSON-Bibliothek, die Unterstützung für Kotlin-Datenklassen bietet. Um Moshi einzurichten, fügen Sie hinzu:

dependencies {
    implementation("com.squareup.moshi:moshi-kotlin:1.8.0")
    kapt("com.squareup.moshi:moshi-kotlin-codegen:1.8.0")
}

Ein Beispiel:

import com.squareup.moshi.JsonClass
import com.squareup.moshi.Moshi
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory

@JsonClass(generateAdapter = true)
data class Person(val name: String, val age: Int)

val moshi = Moshi.Builder()
        .add(KotlinJsonAdapterFactory())
        .build()

val personAdapter = moshi.adapter(Person::class.java)
val dennis = Person("Dennis", 42)
val json  = personAdapter.toJson(dennis)
println(json)
val dennisFromJson = personAdapter.fromJson("""{"name":"Dennis","age":42}""")
println(dennisFromJson)

Fazit

Kotlin ist eine sehr schöne Programmiersprache. Die Syntax und die Funktionen der Sprache erinnern mich an die Programmiersprachen Groovy und Scala. Der beste Vergleich wäre vielleicht, dass es sich um eine Mischung aus diesen beiden Sprachen handelt. Kotlin ist sowohl für die JVM als auch für die Android-Plattform verfügbar und es gibt ein natives Kotlin-Projekt, um Kotlin für Systemprogrammierer verfügbar zu machen.
Eine Funktion, die ich vermisse, ist der Musterabgleich - ein Mechanismus zur Überprüfung eines Wertes anhand eines Musters. Es ist in Kotlin nicht möglich, Datenklassen mit einem Muster abzugleichen. Der Musterabgleich ist eine großartige Funktion, die der Sprache hoffentlich noch hinzugefügt wird.
Kotlin bietet weder Implicits noch implizite Auflösung, eine Funktion, die den Code wirklich aufräumen kann, wenn der Code Daten wie bei der JSON- oder AVRO-Serialisierung verarbeitet.
Die Arrow-Bibliothek bietet funktionale Datenstrukturen und Typklassen für diejenigen, die ohne Semigruppen, Monoide, Funktoren, Monaden und dergleichen nicht leben können.
Was ich an Kotlin wirklich mag, sind Coroutines, eine Kotlin-Funktion, die asynchrone Rückrufe für langlaufende Aufgaben, wie z.B. Datenbank- oder Netzwerkzugriffe, in sequenziellen Code umwandelt.
Für Projekte, die nicht den Aufwand von Scala benötigen, aber die prägnante Syntax und Flexibilität einer modernen Programmiersprache auf der JVM wünschen, würde ich zu Kotlin raten.

Verfasst von

Dennis Vriend

Contact

Let’s discuss how we can support your journey.