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.

Domande da colloquio su Kotlin 2.3 per Android con destrutturazione e concetti KMP

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à.

Cosa cambia in Kotlin 2.3

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:

User.ktkotlin
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:

build.gradle.ktskotlin
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:

NameBasedDestructuring.ktkotlin
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?"

shared/src/commonMain/kotlin/com/app/network/ApiClient.ktkotlin
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())
    }
}
shared/src/androidMain/kotlin/com/app/network/HttpClient.android.ktkotlin
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.

ContextParameters.ktkotlin
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.

FlowComparison.ktkotlin
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:

UserViewModel.ktkotlin
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:

UiState.ktkotlin
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 @nativeInvoke permette 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?"

ScopeFunctions.ktkotlin
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.

NullSafety.ktkotlin
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 StateFlow vs SharedFlow, WhileSubscribed e structured concurrency
  • Le sealed interface modellano lo stato UI con esaustività a tempo di compilazione. Preferire sealed interface rispetto a sealed 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

#kotlin
#android
#interview
#kmp
#kotlin-multiplatform
#coroutines

Condividi

Articoli correlati