Top-Fehler von Anfängern in Kotlin: Fortgeschrittenes Niveau
Kotlin ist eine moderne und prägnante Sprache, die Java in der Android-Entwicklung und im Backend aktiv verdrängt. Ihre Flexibilität spielt jedoch Anfängern, die von anderen Sprachen wechseln, oft einen Streich. In diesem Artikel analysieren wir nicht offensichtliche, aber kritische Fehler, die Entwickler machen, die bereits die grundlegende Syntax beherrschen. Sie erfahren, wie Sie Probleme mit Coroutinen, sealed classes, inline-Funktionen und delegierten Eigenschaften vermeiden. Jeder Abschnitt enthält konkrete Codebeispiele und Empfehlungen.
1. Falsche Verwendung von Coroutinen: Speicherlecks und Kontextverlust
Coroutinen sind ein mächtiges Werkzeug für Asynchronität, aber ihre falsche Anwendung führt zu Speicherlecks und schwer zu findenden Bugs. Der häufigste Fehler ist das Starten einer Coroutine ohne Bindung an den Lebenszyklus der Komponente.
Fehler: Globaler Scope in einer Activity
// SCHLECHT: Die Coroutine lebt länger als die Activityclass MyActivity : AppCompatActivity() { fun loadData() { GlobalScope.launch { val data = fetchFromNetwork() withContext(Dispatchers.Main) { textView.text = data // Speicherleck, wenn die Activity bereits zerstört wurde } } }}Lösung: Verwendung von lifecycleScope oder viewModelScope
// GUT: Die Coroutine wird bei Zerstörung der Activity abgebrochenclass MyActivity : AppCompatActivity() { fun loadData() { lifecycleScope.launch { val data = withContext(Dispatchers.IO) { fetchFromNetwork() } textView.text = data } }}Tipp: Verwenden Sie immer einen CoroutineScope, der an den Lebenszyklus gebunden ist. Für ViewModel — viewModelScope, für Activity/Fragment — lifecycleScope. Verwenden Sie GlobalScope niemals in der Produktion.
2. Missbrauch von Null Safety: implizite Annahmen
Kotlin ist bekannt für seine Null Safety, aber Anfänger erzeugen oft ein falsches Sicherheitsgefühl. Ein Fehler ist die Verwendung des !!-Operators, wo man mit sicheren Aufrufen auskommen könnte.
Fehler: Ignorieren von nullable Typen
// SCHLECHT: Kann eine NullPointerException auslösenfun processUser(user: User?) { val name = user!!.name println(name)}Lösung: Verwendung des Elvis-Operators oder von let
// GUT: Sicheres Extrahierenfun processUser(user: User?) { val name = user?.name ?: "Unknown" println(name) // Oder mit let: user?.let { u -> println(u.name) }}Wichtig: Der !!-Operator ist nur in Tests gerechtfertigt oder wenn Sie zu 100% sicher sind, dass der Wert nicht null ist (z.B. nach einer Prüfung in if). Verwenden Sie in anderen Fällen ?.let, ?: oder requireNotNull().
3. Falsche Verwendung von sealed classes und when
Sealed classes sind eine hervorragende Möglichkeit, begrenzte Hierarchien zu modellieren. Anfänger vergessen jedoch oft, dass when ein Ausdruck ist, und berücksichtigen nicht alle Zweige.
Fehler: Fehlende Zweige in when
sealed class Result { data class Success(val data: String) : Result() data class Error(val message: String) : Result() object Loading : Result()}
// SCHLECHT: Der Compiler warnt nicht vor dem Fehlen von Loadingfun handleResult(result: Result) { when (result) { is Result.Success -> println(result.data) is Result.Error -> println(result.message) // Loading vergessen! }}Lösung: Verwendung von when als Ausdruck
// GUT: Der Compiler zwingt zur Behandlung aller Zweigefun handleResult(result: Result): String { return when (result) { is Result.Success -> result.data is Result.Error -> result.message is Result.Loa