Kotlin 2.3 voor Android: Naamgebaseerde Destructurering, KMP en Sollicitatievragen 2026
Kotlin 2.3 sollicitatievragen over naamgebaseerde destructurering, Kotlin Multiplatform, contextparameters, coroutines en Flow. Voorbereiding op Android-ontwikkelaarsgesprekken in 2026 met praktische codevoorbeelden.

Kotlin 2.3 sollicitatievragen behoren in 2026 tot de meest gezochte onderwerpen voor Android-ontwikkelaarsposities. Met naamgebaseerde destructureringsdeclaraties, gestabiliseerde contextparameters en een volwassen Kotlin Multiplatform-ecosysteem verwachten interviewers dat kandidaten deze functionaliteiten beheersen.
Kotlin 2.3.20, uitgebracht in maart 2026, introduceert naamgebaseerde destructureringsdeclaraties, wijzigingen in de overload-resolutie voor contextparameters en verbeterde KMP-interoperabiliteit met C en TypeScript. Deze features komen regelmatig terug in senior Android-sollicitatiegesprekken.
Naamgebaseerde destructurering: de meestgestelde Kotlin 2.3 sollicitatievraag
Voor Kotlin 2.3 waren destructureringsdeclaraties gebaseerd op positiegebonden componentN()-functies. Dit veroorzaakte een bekend probleem: het wijzigen van de volgorde van properties in een data class brak bestaande destructureringspunten zonder waarschuwing.
De klassieke sollicitatievraag presenteert precies dit scenario:
data class User(val username: String, val email: String)
fun main() {
val user = User("alice", "alice@example.com")
// Position-based: order matters, not names
val (email, username) = user
println(email) // Prints "alice" -- wrong!
println(username) // Prints "alice@example.com" -- wrong!
}Kotlin 2.3.20 lost dit op met naamgebaseerde destructurering. Drie compilermodi bepalen het gedrag:
kotlin {
compilerOptions {
// Mode 1: Explicit syntax only
freeCompilerArgs.add("-Xname-based-destructuring=only-syntax")
// Mode 2: Warns on name mismatch
// freeCompilerArgs.add("-Xname-based-destructuring=name-mismatch")
// Mode 3: Full name-based by default
// freeCompilerArgs.add("-Xname-based-destructuring=complete")
}
}In de complete-modus gebruiken ronde haakjes naamgebaseerde matching, terwijl vierkante haakjes het positiegebaseerde gedrag behouden:
data class User(val username: String, val email: String)
fun main() {
val user = User("alice", "alice@example.com")
// Name-based: matches by property name
val (email, username) = user
println(email) // "alice@example.com" -- correct
println(username) // "alice" -- correct
// Position-based: square brackets preserve old behavior
val [first, second] = user
println(first) // "alice" (component1)
println(second) // "alice@example.com" (component2)
}Een sterk antwoord in een sollicitatiegesprek legt alle drie de modi uit en identificeert wanneer elke modus van toepassing is: only-syntax voor geleidelijke migratie, name-mismatch voor het opsporen van bugs in bestaande code en complete voor nieuwe projecten.
Kotlin Multiplatform sollicitatievragen voor Android-ontwikkelaars
KMP heeft de experimentele fase achter zich gelaten. Google ondersteunt het officieel voor het delen van bedrijfslogica tussen Android en iOS, en de meeste nieuwe cross-platform projecten hanteren standaard een shared-core-architectuur.
Een typische sollicitatievraag luidt: "Hoe zou je een KMP-module structureren voor gedeelde networking?"
import io.ktor.client.*
import io.ktor.client.request.*
import io.ktor.client.statement.*
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
@Serializable
data class UserProfile(
val id: String,
val displayName: String,
val avatarUrl: String?
)
// Expect/actual pattern for platform-specific HTTP engine
expect fun createHttpClient(): HttpClient
class ApiClient {
private val client = createHttpClient()
private val json = Json { ignoreUnknownKeys = true }
// Suspend function shared across Android and iOS
suspend fun fetchProfile(userId: String): UserProfile {
val response = client.get("https://api.example.com/users/$userId")
return json.decodeFromString(response.bodyAsText())
}
}import io.ktor.client.*
import io.ktor.client.engine.okhttp.*
// Android uses OkHttp engine
actual fun createHttpClient(): HttpClient = HttpClient(OkHttp) {
engine {
config {
retryOnConnectionFailure(true)
}
}
}Interviewers beoordelen of de kandidaat het expect/actual-mechanisme, platformspecifieke afhankelijkheden en de grens tussen gedeelde en platformspecifieke code begrijpt.
Een andere veelgestelde vraag gaat over Swift Export, dat in 2026 aanzienlijk is doorontwikkeld. Kotlin suspend-functies worden nu rechtstreeks gemapt op Swift async/await, en sealed classes komen overeen met Swift enums met bijbehorende waarden.
Contextparameters en wijzigingen in de overload-resolutie
Contextparameters vervangen de verouderde context receivers API. Kotlin 2.3.20 introduceerde een breaking change in de overload-resolutie: declaraties met contextparameters worden niet langer behandeld als specifieker dan declaraties zonder.
class Logger {
fun info(msg: String) = println("INFO: $msg")
}
class TransactionScope {
fun execute(block: () -> Unit) = block()
}
// Function with context parameter
context(logger: Logger)
fun saveUser(id: Int) {
logger.info("Saving user $id")
}
// Overload without context -- now ambiguous in 2.3.20
fun saveUser(id: Int) {
println("Saving user $id (no logger)")
}
fun main() {
val logger = Logger()
// This now produces an ambiguity error in Kotlin 2.3.20
// context(logger) { saveUser(1) }
// Fix: rename or qualify the context-aware variant
}Interviewers gebruiken dit onderwerp om het bewustzijn van breaking changes en migratiestrategieën te toetsen. De kernboodschap: vertrouwen op impliciete contextparameterresolutie om niet-contextuele overloads te overschaduwen, werkt niet meer.
Coroutines en Flow: nog steeds het belangrijkste Android-sollicitatieonderwerp
Ondanks de nieuwe functies in Kotlin 2.3 blijven coroutines en Flow het meest geteste gebied. Sollicitatievragen onderzoeken doorgaans het verschil tussen cold en hot flows, structured concurrency en cancellation.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
// Cold Flow: emits only when collected
fun userUpdates(): Flow<String> = flow {
println("Flow started") // Runs per collector
emit("User logged in")
delay(1000)
emit("User updated profile")
}
// Hot Flow: emits independently of collectors
class UserRepository {
// StateFlow holds the latest value
private val _state = MutableStateFlow("idle")
val state: StateFlow<String> = _state.asStateFlow()
// SharedFlow broadcasts to multiple collectors
private val _events = MutableSharedFlow<String>()
val events: SharedFlow<String> = _events.asSharedFlow()
suspend fun login() {
_state.value = "loading"
delay(500)
_state.value = "authenticated"
_events.emit("login_success")
}
}Een vervolgvraag gaat vaak over het veilig verzamelen van flows in Android:
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
class UserViewModel(private val repo: UserRepository) : ViewModel() {
// Expose state to Compose UI
val uiState: StateFlow<String> = repo.state
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5000),
initialValue = "idle"
)
init {
// Collect events safely within ViewModel scope
viewModelScope.launch {
repo.events.collect { event ->
// Handle one-time events
println("Event received: $event")
}
}
}
}De WhileSubscribed(5000)-strategie houdt de upstream 5 seconden actief nadat de laatste subscriber is verdwenen, waardoor onnodige herstarts tijdens configuratiewijzigingen zoals schermrotatie worden voorkomen.
Klaar om je Android gesprekken te halen?
Oefen met onze interactieve simulatoren, flashcards en technische tests.
Sealed classes en exhaustive when: pattern matching in sollicitatiegesprekken
Sealed classes verschijnen in vrijwel elk Android-sollicitatiegesprek. De vraag verzoekt kandidaten doorgaans om een UI-state te modelleren:
sealed interface UiState<out T> {
data object Loading : UiState<Nothing>
data class Success<T>(val data: T) : UiState<T>
data class Error(val message: String, val retry: (() -> Unit)? = null) : UiState<Nothing>
}
// Usage in ViewModel
fun loadUsers(): Flow<UiState<List<UserProfile>>> = flow {
emit(UiState.Loading)
try {
val users = apiClient.fetchUsers()
emit(UiState.Success(users))
} catch (e: Exception) {
emit(UiState.Error(
message = e.localizedMessage ?: "Unknown error",
retry = { /* trigger reload */ }
))
}
}In Kotlin zijn when-expressies over sealed types exhaustief tijdens compilatie. Het toevoegen van een nieuw subtype dwingt af dat het overal wordt afgehandeld, waardoor een hele categorie runtime-bugs wordt geëlimineerd. Interviewers controleren specifiek of de kandidaat sealed interface (niet sealed class) gebruikt voor dit patroon, omdat interfaces flexibelere hiërarchieën mogelijk maken.
Kotlin/Wasm en cross-platform compilatiedoelen
Kotlin/Wasm heeft de Beta-status bereikt en biedt bijna-native prestaties in browsers. Hoewel het voor Android-ontwikkelaars nog geen dagelijks onderwerp is, wordt het wel gevraagd bij bedrijven met web- en mobiele producten.
Belangrijke feiten voor het sollicitatiegesprek:
- Kotlin 2.3.20 leverde 4,6x snellere string-interpolatie in Wasm via JS String builtins
- Binaire grootten zijn met ongeveer 5% afgenomen
- Clean builds draaien 65% sneller, incrementele builds 21% sneller
- De
@nativeInvoke-annotatie stelt Kotlin-objecten in staat om als JavaScript-functies te fungeren
Kotlin/JS kreeg bovendien de mogelijkheid om Kotlin-interfaces vanuit TypeScript te implementeren, waarmee een eerdere beperking werd opgeheven. In combinatie met SWC-ondersteuning voor transpilatie dekt Kotlin nu Android, iOS (via KMP), Web (via Wasm/JS) en server-side doelen vanuit één enkele codebase.
Scope functions: een misleidend eenvoudig sollicitatiefilter
Scope functions (let, run, with, apply, also) lijken eenvoudig maar onderscheiden ervaren Kotlin-ontwikkelaars. De sollicitatievraag luidt doorgaans: "Wanneer gebruik je let in plaats van apply?"
data class Request(
var url: String = "",
var method: String = "GET",
var headers: MutableMap<String, String> = mutableMapOf(),
var body: String? = null
)
fun buildRequest(): Request {
// apply: configure an object, returns the object
return Request().apply {
url = "https://api.example.com/users"
method = "POST"
headers["Content-Type"] = "application/json"
body = "{\"name\": \"Alice\"}"
}
}
fun processNullable(input: String?) {
// let: transform nullable, returns lambda result
val length = input?.let { value ->
println("Processing: $value")
value.trim().length
} ?: 0
// also: side effects, returns the original object
input?.also { println("Logging input: $it") }
// run: execute a block with receiver, returns lambda result
val result = input?.run {
// 'this' is the string
uppercase().take(10)
}
}Het besliskader: apply voor objectconfiguratie (retourneert de receiver), let voor null-veilige transformaties (retourneert het lambda-resultaat), also voor neveneffecten (retourneert de receiver), run voor het berekenen van een resultaat met receivercontext.
Null safety en het gevaar van de double-bang-operator
Null safety blijft een fundamenteel sollicitatieonderwerp. De vraag "Waarom is !! gevaarlijk?" test of een kandidaat het typesysteem van Kotlin werkelijk begrijpt.
fun findUser(id: String): User? {
// Returns null if user not found
return database.queryUser(id)
}
// Bad: !! defeats the purpose of null safety
fun riskyApproach(id: String) {
val user = findUser(id)!! // NullPointerException if null
println(user.username)
}
// Good: handle null explicitly
fun safeApproach(id: String) {
val user = findUser(id) ?: run {
println("User not found")
return
}
println(user.username)
}
// Good: provide default with Elvis operator
fun displayName(id: String): String {
return findUser(id)?.username ?: "Anonymous"
}Een volledig antwoord vermeldt dat !! alleen in testcode of op platforminterop-grenzen mag voorkomen, waar null daadwerkelijk onmogelijk is.
Begin met oefenen!
Test je kennis met onze gespreksimulatoren en technische tests.
Conclusie
- Naamgebaseerde destructurering in Kotlin 2.3.20 elimineert positieafhankelijke bugs. Alle drie de compilermodi moeten bekend zijn:
only-syntax,name-mismatch,complete - KMP is productiestabiel in 2026. Vragen over expect/actual, gedeelde module-architectuur en Swift Export-interoperabiliteit zijn te verwachten
- Contextparameters hebben context receivers vervangen. De wijziging in de overload-resolutie in 2.3.20 is een veelgebruikte strikvraag
- Coroutines en Flow domineren Android-sollicitatiegesprekken. Beheersing van
StateFlowvsSharedFlow,WhileSubscribeden structured concurrency is vereist - Sealed interfaces modelleren UI-state met compile-time exhaustiviteit. Gebruik
sealed interfacebovensealed class - Scope functions vereisen een duidelijk besliskader: receiver vs argument, retourwaarde vs receiver
- Null safety is niet onderhandelbaar. Kunnen uitleggen waarom
!!het typesysteem ondermijnt en alternatieven kunnen demonstreren
Begin met oefenen!
Test je kennis met onze gespreksimulatoren en technische tests.
Tags
Delen
Gerelateerde artikelen

De 20 meest gestelde Jetpack Compose interviewvragen in 2026
De 20 meest gestelde Jetpack Compose interviewvragen: recomposition, state management, navigatie, performance en architectuurpatronen.

Kotlin Coroutines voor Android: Complete Gids 2026
Uitgebreide gids over Kotlin coroutines voor Android-ontwikkeling: suspend-functies, scopes, dispatchers, Flow en geavanceerde patronen.

Jetpack Compose: Geavanceerde Animaties Stap voor Stap
Volledige gids voor geavanceerde Compose-animaties: transities, AnimatedVisibility, Animatable, gestures en performance voor vloeiende Android-interfaces.