Prägnant, sicher und die erste Wahl für Android
Ausführen: Online im Kotlin Playground (play.kotlinlang.org) oder lokal mit IntelliJ IDEA bzw. kotlinc hallo.kt -include-runtime -d hallo.jar und java -jar hallo.jar.
fun main(), kein Semikolon nötig"$name" und "${ausdruck}"data class, Lambdas, Typinferenzfun main() {
println("Hallo Kotlin!")
print("ohne Zeilenumbruch")
println()
val name = "Mia"
println("Hallo $name, 2 + 3 = ${2 + 3}")
}val unveränderlich, var veränderlich; const val für Konstantenval x = 42; explizit: val x: Int = 42toInt(), toDouble(), toLong()toIntOrNull() für sichere Umwandlung7 / 2 = 3fun main() {
val name = "Mia" // Typ wird erschlossen: String
var punkte = 10
punkte += 5
// name = "Tom" // Fehler: val kann nicht neu zugewiesen werden
val alter: Int = 17 // Typ ausdrücklich
println("$name $punkte $alter")
val spaeter: String // Zuweisung später, genau einmal
spaeter = "gesetzt"
println(spaeter)
}substring, split, replace, contains, trim, repeat, format"""...""" und trimIndent()if und when liefern Werte (kein ? : nötig)when mit Wert, Bereich (in), Typ (is) und ohne Argumentfor (x in 1..10), downTo, step, until, Labels mit break@namefun main() {
val s = "Hallo Welt"
println("${s.length} ${s[0]} ${s.last()} ${s.substring(0, 5)} ${s.toUpperCase()} ${s.toLowerCase()}")
println(s.replace("Welt", "Kotlin"))
println(s.contains("Welt"))
println(s.startsWith("Hal"))
println(s.indexOf('W'))
println(s.split(" "))
println(s.reversed())
println(" x ".trim() + "|")
println("ab".repeat(3))
println("a,b;c".split(",", ";"))
println("kotlin".capitalize())
println(s.take(5) + "-" + s.drop(6))
println("Mia" + " " + 17)
println("42".padStart(5, '0'))
println("abc" < "abd")
println("Name: %s, Alter: %d".format("Mia", 17))
println(listOf("x", "y", "z").joinToString(" | "))
val roh = """
Mehrzeilig,
"Anführungszeichen" und \n bleiben roh.
""".trimIndent()
println(roh)
println("Tab:\tText \\ \" A")
}fun name(p: Typ = std): Rückgabetyp; Ausdruckskörper = ausdruckvararg und * (Spread){ x -> ... } / it; Funktionstypen (Int) -> Int; Referenzen ::namefun String.foo()tailrec, infix, operator, inline für Spezialfällefun addiere(a: Int, b: Int): Int {
return a + b
}
fun quadrat(x: Int) = x * x // Ausdruckskörper, Typ wird erschlossen
fun gruss(name: String = "Welt", anrede: String = "Hallo"): String = "$anrede, $name!"
fun protokolliere(text: String) { // Unit = kein Rückgabewert (wie void)
println("[LOG] $text")
}
fun summe(vararg zahlen: Int): Int = zahlen.sum()
fun minMax(liste: List<Int>): Pair<Int, Int> = Pair(liste.min() ?: 0, liste.max() ?: 0)
fun main() {
println(addiere(2, 3))
println(quadrat(7))
println(gruss())
println(gruss("Mia"))
println(gruss(anrede = "Hi", name = "Tom")) // benannte Argumente
protokolliere("gestartet")
println(summe(1, 2, 3, 4))
val zahlen = intArrayOf(5, 6)
println(summe(*zahlen)) // Spread-Operator *
val (klein, gross) = minMax(listOf(4, 9, 1)) // Destrukturierung
println("$klein $gross")
}Typ ist nie null, Typ? kann null sein?. sicherer Aufruf, ?: Elvis, ?.let { } für Blöcke!! vermeiden: besser prüfen oder ?: nutzen== null und islateinit und by lazy für verzögerte Initialisierungfun main() {
val a: String = "Text"
val b: String? = null
// val c: String = null // Fehler: Null kann kein Wert vom Typ String sein
println(a.length)
// println(b.length) // Fehler: nur sicherer Aufruf mit ?. erlaubt
println(b?.length) // sicherer Aufruf: null statt Absturz
println(b ?: "Standard") // Elvis-Operator: Ersatz bei null
println(b?.length ?: 0)
}listOf/setOf/mapOf (fest) und mutableListOf ... (veränderbar)m["k"], to, for ((k, v) in m)map, filter, reduce, fold, groupBy, sortedBy, zip, flatMap, associateasSequence() für lazy VerarbeitungIntArray, Array<T>) für feste Größe und Leistungfun main() {
val feste = listOf("Apfel", "Birne", "Kirsche") // nicht veränderbar
val liste = mutableListOf(5, 3, 9)
liste.add(1)
liste.add(0, 42)
liste.remove(9)
liste[1] = 7
println("$feste ${feste.size} ${feste[0]} ${feste.first()} ${feste.last()}")
println(liste)
println(liste.sorted())
println(liste.sortedDescending())
println(liste.reversed())
println(liste.contains(7))
println(7 in liste)
println(liste.indexOf(7))
println(liste.getOrNull(10))
println(liste.subList(1, 3))
println(liste + listOf(100))
println(liste - 7)
println(emptyList<Int>().isEmpty())
for ((i, x) in liste.withIndex()) print("$i:$x ")
println()
}init-Blöcke, Eigenschaften mit eigenem get/setfinal: für Vererbung open, Überschreiben mit overrideabstract, internal, private set steuern Struktur und Sichtbarkeitcompanion object statt static, object für Singletonsrequire/check prüfen Voraussetzungenclass Konto(val inhaber: String, startStand: Double = 0.0) {
var stand: Double = startStand
private set // nur innerhalb der Klasse änderbar
val reich: Boolean
get() = stand > 1000 // berechnete Eigenschaft
init {
println("Konto für $inhaber angelegt")
}
fun einzahlen(betrag: Double) {
require(betrag > 0) { "Betrag muss positiv sein" } // Voraussetzung prüfen
stand += betrag
}
override fun toString() = "$inhaber: ${"%.2f".format(stand)}"
}
fun main() {
val k = Konto("Mia", 100.0)
k.einzahlen(50.0)
println(k)
println(k.reich)
try {
k.einzahlen(-5.0)
} catch (e: IllegalArgumentException) {
println("Fehler: ${e.message}")
}
// k.stand = 5.0 // Fehler: private set
}data class: equals, toString, copy, Destrukturierung inklusiveenum class mit Eigenschaften und Methoden; values(), valueOf()sealed class + when ohne else: Der Compiler prüft die Vollständigkeit== vergleicht Inhalte, === Referenzentypealias für lesbare Typnamendata class Person(val name: String, val alter: Int, val ort: String = "unbekannt")
fun main() {
val a = Person("Mia", 17)
val b = Person("Mia", 17)
println(a)
println(a == b) // Inhaltsvergleich
println(a === b) // Identität
val c = a.copy(alter = 18, ort = "Berlin")
println(c)
val (name, alter) = c // Destrukturierung
println("$name ist $alter")
println(setOf(a, b).size)
println(a.hashCode() == b.hashCode())
}<T>, Schranken <T : Comparable<T>>, Varianz out/inby statt VererbungDelegates.observable, vetoable und lazy für Eigenschafteninterface Sprechend {
val name: String // abstrakte Eigenschaft
fun spricht(): String
fun vorstellen() = "$name: ${spricht()}" // Standardimplementierung
}
interface Laufend { fun laeuft() = "läuft" }
class Mensch(override val name: String) : Sprechend, Laufend {
override fun spricht() = "Hallo"
}
class Roboter : Sprechend {
override val name = "R2"
override fun spricht() = "Piep"
}
fun main() {
val liste: List<Sprechend> = listOf(Mensch("Mia"), Roboter())
liste.forEach { println(it.vorstellen()) }
println(Mensch("Tom").laeuft())
}let/also (mit it), run/with/apply (mit this)apply konfiguriert Objekte, let verarbeitet Nullbaresrequire, check, runCatching, takeIf für robuste Logikclass Auto { var farbe = ""; var ps = 0; override fun toString() = "$farbe/$ps" }
fun main() {
val auto = Auto().apply { farbe = "rot"; ps = 150 } // konfigurieren
println(auto)
val text: String? = "42"
val zahl = text?.let { it.toInt() * 2 } // nur wenn nicht null
println(zahl)
val laenge = "Kotlin".run { length + 1 }
println(laenge)
with(auto) { println("Farbe $farbe, $ps PS") }
val liste = mutableListOf(1, 2).also { println("vorher: $it") }.apply { add(3) }
println(liste)
println(listOf(3, 1, 2).sorted().also { println("sortiert") }.first())
}try ist ein Ausdruckuse schließt Ressourcen automatischFile.readText, readLines, writeText, appendText für Dateienclass MeinFehler(msg: String) : Exception(msg)
fun parse(s: String): Int = try {
s.toInt()
} catch (e: NumberFormatException) {
-1
} finally {
println("geprüft: $s")
}
fun main() {
println(parse("42"))
println(parse("x"))
try {
throw MeinFehler("eigener Fehler")
} catch (e: MeinFehler) {
println("${e.javaClass.simpleName}: ${e.message}")
}
try {
val l = listOf(1)
println(l[5])
} catch (e: IndexOutOfBoundsException) {
println("Index ungültig")
} catch (e: Exception) {
println("anderes")
}
val ergebnis = try { 1 / 0 } catch (e: ArithmeticException) { 0 }
println(ergebnis)
}suspend, launch, async, runBlocking, delay sind die Grundbausteine der Coroutinendependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1")
}val vor var, Typen ableiten lassen, Nullbarkeit im Typwhen statt Kettenval x = 1 // unveränderlich
var y = 2 // veränderlich
const val C = 3 // Konstante (oberste Ebene)
val t: String? = null
fun f(a: Int, b: Int = 0): Int = a + b