So meistern Sie das Kotlin-Vorstellungsgespräch: Top-Fragen für Fortgeschrittene
\n\nEin Vorstellungsgespräch für eine Stelle als Kotlin-Entwickler ist nicht nur eine Überprüfung der Syntax. Auf fortgeschrittenem Niveau möchten Interviewer ein tiefes Verständnis der Sprache, ihrer Besonderheiten und die Fähigkeit sehen, effizienten, prägnanten und sicheren Code zu schreiben. In diesem Artikel analysieren wir die wichtigsten Themen, die häufig in technischen Vorstellungsgesprächen vorkommen: Coroutinen, Inline-Funktionen, Sealed-Klassen, Delegierung und Tricks mit Lambda-Ausdrücken. Das Material wurde für das Bildungsportal PythonLib erstellt, wo wir Entwicklern helfen, ihr Wissen zu systematisieren.
\n\n1. Coroutinen (Coroutines) und Structured Concurrency
\nCoroutinen sind die Grundlage der asynchronen Programmierung in Kotlin. Fragen zu diesem Thema zeigen, ob Sie verstehen, wie der Scheduler, der Kontext und die Fehlerbehandlung funktionieren.
\n\nWas ist Structured Concurrency und wozu wird es benötigt?
\nStructured Concurrency (strukturierte Nebenläufigkeit) ist ein Prinzip, bei dem der Lebenszyklus einer Coroutine an einen Gültigkeitsbereich (Scope) gebunden ist. Wenn die übergeordnete Coroutine abgebrochen wird, werden alle untergeordneten Aufgaben automatisch abgebrochen. Dies verhindert Speicherlecks und macht den Code vorhersagbar.
\n\nfun main() = runBlocking {\n launch {\n delay(1000)\n println("Aufgabe 1 abgeschlossen")\n }\n launch {\n delay(500)\n println("Aufgabe 2 abgeschlossen")\n }\n println("Hauptthread wird nicht blockiert")\n}\n\n\nUnterschied zwischen launch und async
\nlaunch startet eine Coroutine, die kein Ergebnis zurückgibt (Unit). async gibt ein Deferred zurück, aus dem das Ergebnis über await() abgerufen werden kann. async eignet sich für parallele Berechnungen.
val deferred1 = async { calculateSum(10, 20) }\nval deferred2 = async { calculateSum(30, 40) }\nval result = deferred1.await() + deferred2.await()\nprintln("Summe: $result")\n\n\nFehlerbehandlung in Coroutinen
\nVerwenden Sie try-catch innerhalb der Coroutine oder CoroutineExceptionHandler für die globale Behandlung. Es ist wichtig zu beachten, dass Ausnahmen in launch die Hierarchie nach oben propagieren, während sie in async bis zum Aufruf von await() gespeichert werden.
val handler = CoroutineExceptionHandler { _, exception ->\n println("Fehler: ${exception.message}")\n}\n\nfun main() = runBlocking {\n val job = launch(handler) {\n throw RuntimeException("Etwas ist schiefgelaufen")\n }\n}\n\n\n2. Inline-Funktionen, reified und crossinline
\nDiese Mechanismen ermöglichen die Optimierung der Leistung und die Arbeit mit Generics zur Laufzeit. Interviewer fragen oft nach dem Unterschied zwischen inline, noinline und crossinline.
Wozu werden Inline-Funktionen benötigt?
\nInline-Funktionen setzen den Funktionskörper direkt an der Aufrufstelle ein. Dadurch entfallen die Gemeinkosten für die Erstellung von Lambda-Objekten. Dies ist besonders nützlich für Higher-Order-Funktionen.
\n\ninline fun measureTime(action: () -> Unit) {\n val start = System.currentTimeMillis()\n action()\n println("Zeit: ${System.currentTimeMillis() - start} ms")\n}\n\n\nWas ist reified?
\nMit reified können Sie innerhalb einer Inline-Funktion Informationen über den Typ abrufen, was bei normalen Generics aufgrund der Typenlöschung nicht möglich ist.
inline fun <reified T> isInstance(value: Any): Boolean {\n return value is T\n}\n\nfun main() {\n println(isInstance<String>("Hello")) // true\n}\n\n\nUnterschied zwischen noinline und crossinline
\n- \n
noinline– verbietet das Inlining einer bestimmten Lambda-Funktion (z. B. wenn sie an eine andere Funktion übergeben wird). \n crossinline– erlaubt Inlining, verbietet aber die nicht-lokale Rückkehr (non-local return) aus der Lambda-Funktion, was für asynchrone Aufrufe sicher ist. \n