Einführung in die funktionale Programmierung mit Kotlin
Kotlin ist eine moderne multiparadigmatische Sprache, die objektorientierte und funktionale Programmierung nahtlos miteinander verbindet. Der funktionale Stil ermöglicht es, vorhersehbareren, prägnanteren und testbareren Code zu schreiben. In diesem Artikel behandeln wir die wichtigsten Konzepte der funktionalen Programmierung (FP) in Kotlin: reine Funktionen, Unveränderlichkeit von Daten, Funktionen höherer Ordnung und die Arbeit mit Collections mittels map, filter und fold. Das Material richtet sich an Entwickler, die bereits mit den Grundlagen der Kotlin-Syntax vertraut sind.
Reine Funktionen und Unveränderlichkeit
Was ist eine reine Funktion?
Eine reine Funktion ist eine Funktion, die:
- Für dieselben Argumente immer dasselbe Ergebnis zurückgibt (Determinismus).
- Keine Seiteneffekte hat (keinen externen Zustand verändert, keine globalen Variablen liest, keine Ein-/Ausgabe durchführt).
Beispiel einer reinen Funktion:
fun sum(a: Int, b: Int): Int = a + bBeispiel einer unreinen Funktion (abhängig von externem Zustand):
var counter = 0fun impureSum(a: Int, b: Int): Int { counter++ // Seiteneffekt return a + b}Unveränderlichkeit (immutability)
In der FP vermeidet man es, Daten nach ihrer Erstellung zu verändern. In Kotlin werden dafür verwendet:
valanstelle vonvarzur Deklaration unveränderlicher Referenzen.- Unveränderliche Collections:
listOf,mapOf,setOf. - Kopieren von Objekten mit Änderungen mittels
copy()für data-Klassen.
data class User(val name: String, val age: Int)
fun main() { val user = User("Alice", 25) val updatedUser = user.copy(age = 26) // erstellt eine neue Kopie println(user) // User(name=Alice, age=25) println(updatedUser) // User(name=Alice, age=26)}Vorteile der Unveränderlichkeit: vereinfachtes Debugging, Threadsicherheit, Vorhersagbarkeit des Codes.
Funktionen höherer Ordnung und Lambda-Ausdrücke
Funktionen als Werte
In Kotlin können Funktionen als Argumente übergeben, von anderen Funktionen zurückgegeben und in Variablen gespeichert werden. Dies ist die Grundlage des funktionalen Stils.
// Funktion, die eine andere Funktion entgegennimmtfun operateOnNumbers(a: Int, b: Int, operation: (Int, Int) -> Int): Int { return operation(a, b)}
fun main() { val sum = operateOnNumbers(5, 3) { x, y -> x + y } val product = operateOnNumbers(5, 3) { x, y -> x * y } println("Summe: $sum, Produkt: $product")}Lambda-Ausdrücke
Ein Lambda ist eine anonyme Funktion in kompakter Schreibweise. Syntax: { Argumente -> Rumpf }.
val square: (Int) -> Int = { x -> x * x }val result = square(4) // 16
// Bei einem einzelnen Argument kann der implizite Name it verwendet werdenval double: (Int) -> Int = { it * 2 }Eingebaute Funktionen höherer Ordnung
Kotlin bietet viele nützliche Funktionen für die Arbeit mit Collections:
map— transformiert jedes Element.filter— behält Elemente, die eine Bedingung erfüllen.fold— Faltung einer Collection zu einem einzelnen Wert mit einem Start-Akkumulator.
fun main() { val numbers = listOf(1, 2, 3, 4, 5)
// map: quadrieren val squares = numbers.map { it * it } println(squares) // [1, 4, 9, 16, 25]
// filter: nur gerade Zahlen behalten val evens = numbers.filter { it % 2 == 0 } println(evens) // [2, 4]
// fold: Summe aller Elemente val sum = numbers.fold(0) { acc, element -> acc + element } println(sum) // 15
// Methodenverkettung: gerade Quadrate val evenSquares = numbers .filter { it %