Kotlin 2.3 per Android: Destrutturazione Basata sui Nomi, KMP e Domande da Colloquio 2026
Domande da colloquio su Kotlin 2.3 riguardanti la destrutturazione basata sui nomi, Kotlin Multiplatform, parametri di contesto, coroutine e Flow. Preparazione ai colloqui per sviluppatori Android nel 2026 con esempi di codice reali.

Le domande da colloquio su Kotlin 2.3 si posizionano tra gli argomenti più ricercati per le posizioni di sviluppatore Android nel 2026. Con le dichiarazioni di destrutturazione basate sui nomi, i parametri di contesto stabilizzati e un ecosistema Kotlin Multiplatform maturo, gli intervistatori si aspettano che i candidati dimostrino padronanza di queste funzionalità.
Kotlin 2.3.20, rilasciato a marzo 2026, introduce le dichiarazioni di destrutturazione basate sui nomi, modifiche alla risoluzione degli overload per i parametri di contesto e una migliore interoperabilità KMP con C e TypeScript. Queste funzionalità compaiono frequentemente nei colloqui per posizioni Android senior.
Destrutturazione basata sui nomi: la domanda più frequente su Kotlin 2.3
Prima di Kotlin 2.3, le dichiarazioni di destrutturazione si basavano sulle funzioni componentN() posizionali. Questo creava un problema ben noto: modificare l'ordine delle proprietà in una data class rompeva silenziosamente i punti di destrutturazione esistenti.
La domanda classica da colloquio presenta esattamente questo 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 risolve il problema con la destrutturazione basata sui nomi. Tre modalità del compilatore controllano il comportamento:
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")
}
}Con la modalità complete, le parentesi tonde utilizzano il matching basato sui nomi, mentre le parentesi quadre preservano il comportamento posizionale:
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)
}Una risposta convincente durante un colloquio spiega tutte e tre le modalità e identifica quando ciascuna è appropriata: only-syntax per la migrazione graduale, name-mismatch per individuare bug nel codice esistente e complete per i nuovi progetti.
Domande su Kotlin Multiplatform per sviluppatori Android
KMP ha superato la fase sperimentale. Google lo supporta ufficialmente per la condivisione della logica di business tra Android e iOS, e la maggior parte dei nuovi progetti multipiattaforma adotta un'architettura shared-core per impostazione predefinita.
Una domanda tipica da colloquio chiede: "Come struttureresti un modulo KMP per il networking condiviso?"
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)
}
}
}Gli intervistatori valutano se il candidato comprende il meccanismo expect/actual, le dipendenze specifiche della piattaforma e il confine tra codice condiviso e codice di piattaforma.
Un'altra domanda frequente riguarda Swift Export, che si è evoluto significativamente nel 2026. Le funzioni suspend di Kotlin ora si mappano direttamente su Swift async/await, e le sealed class corrispondono agli enum Swift con valori associati.
Parametri di contesto e modifiche alla risoluzione degli overload
I parametri di contesto sostituiscono la deprecata API dei context receivers. Kotlin 2.3.20 ha introdotto una breaking change nella risoluzione degli overload: le dichiarazioni con parametri di contesto non vengono più trattate come più specifiche rispetto a quelle senza.
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
}Gli intervistatori utilizzano questo argomento per valutare la consapevolezza dei candidati riguardo alle breaking change e alle strategie di migrazione. Il punto chiave: affidarsi alla risoluzione implicita dei parametri di contesto per sovrascrivere gli overload non contestuali non funziona più.
Coroutine e Flow: ancora il tema principale nei colloqui Android
Nonostante le novità introdotte da Kotlin 2.3, le coroutine e Flow rimangono l'area più testata. Le domande da colloquio esplorano tipicamente la differenza tra cold e hot flow, la structured concurrency e la 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")
}
}Una domanda di follow-up chiede spesso come raccogliere i flow in modo sicuro 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")
}
}
}
}La strategia WhileSubscribed(5000) mantiene l'upstream attivo per 5 secondi dopo la scomparsa dell'ultimo subscriber, evitando riavvii non necessari durante i cambiamenti di configurazione come la rotazione dello schermo.
Pronto a superare i tuoi colloqui su Android?
Pratica con i nostri simulatori interattivi, flashcards e test tecnici.
Sealed class e when esaustivo: il pattern matching nei colloqui
Le sealed class compaiono in quasi tutti i colloqui Android. La domanda chiede tipicamente ai candidati di modellare uno stato dell'interfaccia utente:
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, le espressioni when sui sealed type sono esaustive a tempo di compilazione. L'aggiunta di un nuovo sottotipo obbliga a gestirlo ovunque, eliminando un'intera categoria di bug a runtime. Gli intervistatori verificano specificamente che il candidato utilizzi sealed interface (non sealed class) per questo pattern, poiché le interfacce consentono gerarchie più flessibili.
Kotlin/Wasm e target di compilazione cross-platform
Kotlin/Wasm ha raggiunto lo stato Beta e offre prestazioni quasi native nei browser. Sebbene non sia ancora un tema quotidiano per gli sviluppatori Android, viene richiesto nelle aziende con prodotti web e mobile.
Fatti chiave per il colloquio:
- Kotlin 2.3.20 ha portato un'interpolazione di stringhe 4,6 volte più veloce in Wasm tramite JS String builtins
- Le dimensioni dei binari sono diminuite di circa il 5%
- I clean build sono il 65% più veloci, i build incrementali il 21% più veloci
- L'annotazione
@nativeInvokepermette agli oggetti Kotlin di funzionare come funzioni JavaScript
Kotlin/JS ha inoltre acquisito la capacità di implementare interfacce Kotlin da TypeScript, rimuovendo una precedente limitazione. Combinato con il supporto SWC per la transpilazione, Kotlin copre ora Android, iOS (tramite KMP), Web (tramite Wasm/JS) e target server-side da un'unica base di codice.
Scope function: un filtro insidiosamente semplice nei colloqui
Le scope function (let, run, with, apply, also) sembrano semplici ma distinguono gli sviluppatori Kotlin esperti. La domanda da colloquio di solito chiede: "Quando si usa let rispetto ad 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)
}
}Lo schema decisionale: apply per la configurazione degli oggetti (restituisce il receiver), let per le trasformazioni null-safe (restituisce il risultato della lambda), also per gli effetti collaterali (restituisce il receiver), run per calcolare un risultato con il contesto del receiver.
Null safety e il pericolo del double-bang
La null safety resta un argomento fondamentale nei colloqui. La domanda "Perché !! è pericoloso?" verifica se un candidato comprende davvero il sistema di tipi di Kotlin.
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"
}Una risposta completa menziona che !! dovrebbe comparire solo nel codice di test o ai confini dell'interoperabilità con la piattaforma, dove il null è genuinamente impossibile.
Inizia a praticare!
Metti alla prova le tue conoscenze con i nostri simulatori di colloquio e test tecnici.
Conclusione
- La destrutturazione basata sui nomi in Kotlin 2.3.20 elimina i bug dipendenti dalla posizione. Tutte e tre le modalità del compilatore devono essere conosciute:
only-syntax,name-mismatch,complete - KMP è stabile in produzione nel 2026. Aspettarsi domande su expect/actual, architettura dei moduli condivisi e interoperabilità Swift Export
- I parametri di contesto hanno sostituito i context receivers. La modifica alla risoluzione degli overload nella 2.3.20 è una classica domanda trabocchetto
- Coroutine e Flow dominano i colloqui Android. Padroneggiare
StateFlowvsSharedFlow,WhileSubscribede structured concurrency - Le sealed interface modellano lo stato UI con esaustività a tempo di compilazione. Preferire
sealed interfacerispetto asealed class - Le scope function richiedono uno schema decisionale chiaro: receiver vs argomento, valore di ritorno vs receiver
- La null safety non è negoziabile. Saper articolare perché
!!mina il sistema di tipi e dimostrare le alternative
Inizia a praticare!
Metti alla prova le tue conoscenze con i nostri simulatori di colloquio e test tecnici.
Tag
Condividi
Articoli correlati

Le 20 domande più frequenti su Jetpack Compose nei colloqui 2026
Le 20 domande più frequenti su Jetpack Compose nei colloqui tecnici: recomposition, gestione dello stato, navigazione, performance e pattern architetturali.

Kotlin Coroutines per Android: Guida Completa 2026
Guida approfondita alle coroutine Kotlin per lo sviluppo Android: funzioni suspend, scope, dispatcher, Flow e pattern avanzati.

Jetpack Compose: Animazioni Avanzate Passo dopo Passo
Guida completa alle animazioni avanzate in Compose: transizioni, AnimatedVisibility, Animatable, gesture e prestazioni per interfacce Android fluide.