# Kotlin 2.3 para Android: Desestructuración por Nombre, KMP y Preguntas de Entrevista 2026 > Preguntas de entrevista sobre Kotlin 2.3 para desarrolladores Android en 2026. Desestructuración por nombre, KMP, parámetros de contexto, Flow y coroutines con ejemplos de código. - Published: 2026-05-06 - Updated: 2026-05-06 - Author: SharpSkill - Tags: kotlin, android, entrevista, kmp, coroutines - Reading time: 9 min --- Kotlin 2.3 representa un avance significativo para el desarrollo Android, introduciendo características que transforman la manera en que los desarrolladores escriben código multiplataforma y manejan la desestructuración de datos. Con el lanzamiento estable de Kotlin 2.3.0 en abril de 2025 y la posterior actualización 2.3.20, JetBrains ha consolidado mejoras que todo desarrollador Android debe dominar para las entrevistas técnicas de 2026. > **Novedades principales en Kotlin 2.3** > > Kotlin 2.3 introduce desestructuración basada en nombres (preview), mejoras sustanciales en Kotlin Multiplatform (KMP), parámetros de contexto optimizados y mejor integración con Compose Multiplatform. La actualización 2.3.20 refina el comportamiento de los parámetros de contexto y añade compatibilidad mejorada con el compilador K2. ## Desestructuración basada en nombres: Resolviendo un problema histórico La desestructuración en Kotlin tradicionalmente opera por posición, lo que genera errores sutiles cuando el orden de las propiedades cambia o cuando los nombres de las variables no coinciden con las propiedades originales. Este problema ha sido fuente de bugs difíciles de detectar en aplicaciones de producción. ```kotlin // User.kt 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! } ``` Este ejemplo ilustra el problema fundamental: aunque las variables se denominan `email` y `username`, Kotlin asigna valores según la posición en la declaración de la data class, no según los nombres. El resultado es una asignación incorrecta que el compilador no detecta. ### Configuración de modos de desestructuración Kotlin 2.3 introduce tres modos de compilación para manejar la transición hacia la desestructuración basada en nombres de forma gradual: ```kotlin // build.gradle.kts 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") } } ``` El modo `only-syntax` permite usar la nueva sintaxis sin cambiar el comportamiento existente. El modo `name-mismatch` emite advertencias cuando los nombres no coinciden, facilitando la identificación de código potencialmente problemático. Finalmente, `complete` activa la desestructuración basada en nombres como comportamiento predeterminado. ### Nueva sintaxis para desestructuración La solución elegante de Kotlin 2.3 utiliza paréntesis para desestructuración basada en nombres y corchetes para mantener el comportamiento posicional: ```kotlin // NameBasedDestructuring.kt 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) } ``` Esta diferenciación sintáctica proporciona control explícito sobre el mecanismo de desestructuración utilizado, eliminando ambigüedades y reduciendo errores en tiempo de ejecución. ## Kotlin Multiplatform: Arquitectura compartida para Android e iOS Kotlin Multiplatform (KMP) alcanza madurez en 2025, permitiendo compartir lógica de negocio entre plataformas mientras se mantiene código nativo para interfaces de usuario. Las entrevistas técnicas actuales evalúan la capacidad de diseñar arquitecturas KMP eficientes. ```kotlin // shared/src/commonMain/kotlin/com/app/network/ApiClient.kt 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()) } } ``` El patrón `expect/actual` constituye el mecanismo fundamental para abstraer implementaciones específicas de plataforma. La declaración `expect` define el contrato en código común, mientras que cada plataforma proporciona su implementación `actual`. ### Implementación específica para Android La implementación Android utiliza OkHttp como motor HTTP, aprovechando su madurez y optimizaciones específicas para la plataforma: ```kotlin // shared/src/androidMain/kotlin/com/app/network/HttpClient.android.kt import io.ktor.client.* import io.ktor.client.engine.okhttp.* // Android uses OkHttp engine actual fun createHttpClient(): HttpClient = HttpClient(OkHttp) { engine { config { retryOnConnectionFailure(true) } } } ``` Esta arquitectura permite que el código de negocio permanezca agnóstico a la plataforma mientras las optimizaciones específicas se encapsulan en módulos dedicados. ## Parámetros de contexto: Cambios importantes en 2.3.20 Los parámetros de contexto representan una evolución de los receptores de contexto, proporcionando inyección de dependencias en tiempo de compilación. Kotlin 2.3.20 introduce cambios en la resolución de sobrecarga que los desarrolladores deben comprender: ```kotlin // ContextParameters.kt 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 } ``` El compilador ahora detecta ambigüedades entre funciones con y sin parámetros de contexto, requiriendo que los desarrolladores sean explícitos en sus diseños de API. ## Coroutines y Flow: Fundamentos para entrevistas técnicas El dominio de coroutines y Flow constituye un requisito esencial para posiciones Android senior. Las entrevistas técnicas frecuentemente evalúan la comprensión de la diferencia entre flujos fríos y calientes. ```kotlin // FlowComparison.kt import kotlinx.coroutines.* import kotlinx.coroutines.flow.* // Cold Flow: emits only when collected fun userUpdates(): Flow = 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 = _state.asStateFlow() // SharedFlow broadcasts to multiple collectors private val _events = MutableSharedFlow() val events: SharedFlow = _events.asSharedFlow() suspend fun login() { _state.value = "loading" delay(500) _state.value = "authenticated" _events.emit("login_success") } } ``` Los flujos fríos ejecutan su bloque productor cada vez que un colector se suscribe, mientras que los flujos calientes mantienen estado independiente de los colectores. `StateFlow` retiene el último valor emitido, ideal para estado de UI, mientras que `SharedFlow` permite configurar replay y buffer para eventos. ### Integración con ViewModel La arquitectura recomendada para aplicaciones Android modernas integra Flow con ViewModel utilizando operadores específicos para el ciclo de vida: ```kotlin // UserViewModel.kt 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 = 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") } } } } ``` El operador `stateIn` convierte un Flow frío en StateFlow, mientras que `SharingStarted.WhileSubscribed(5000)` mantiene la suscripción activa durante 5 segundos después de que el último colector se desconecta, optimizando rotaciones de pantalla. ## Modelado de estados con sealed interface Las sealed interfaces proporcionan un mecanismo type-safe para modelar estados de UI, garantizando que todos los casos sean manejados en tiempo de compilación: ```kotlin // UiState.kt sealed interface UiState { data object Loading : UiState data class Success(val data: T) : UiState data class Error(val message: String, val retry: (() -> Unit)? = null) : UiState } // Usage in ViewModel fun loadUsers(): Flow>> = 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 */ } )) } } ``` Las entrevistas técnicas evalúan la capacidad de diseñar jerarquías de estados que capturen todos los escenarios posibles, incluyendo estados de carga, éxito, error y casos límite. ## Funciones de alcance: Uso idiomático de Kotlin El dominio de las funciones de alcance (`let`, `apply`, `also`, `run`, `with`) diferencia a desarrolladores Kotlin experimentados de principiantes: ```kotlin // ScopeFunctions.kt data class Request( var url: String = "", var method: String = "GET", var headers: MutableMap = 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) } } ``` La función `apply` configura objetos retornando el receptor, ideal para builders. `let` transforma valores nullable retornando el resultado del lambda. `also` ejecuta efectos secundarios retornando el objeto original, útil para logging. `run` combina las características de `let` y `with`. ## Seguridad ante nulos: Patrones correctos e incorrectos La seguridad ante nulos constituye una característica fundamental de Kotlin, pero su uso incorrecto puede introducir bugs en producción: ```kotlin // NullSafety.kt 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" } ``` El operador `!!` (not-null assertion) debe evitarse en código de producción, ya que elimina las garantías de seguridad del sistema de tipos. El operador Elvis (`?:`) proporciona valores predeterminados de forma concisa, mientras que `?.let` y `?.run` permiten ejecutar código condicionalmente sobre valores no nulos. ## Conclusión Kotlin 2.3 introduce mejoras fundamentales que todo desarrollador Android debe dominar para las entrevistas técnicas de 2026: - **Desestructuración basada en nombres** elimina bugs sutiles causados por el orden de propiedades, utilizando paréntesis para coincidencia por nombre y corchetes para comportamiento posicional - **Kotlin Multiplatform** alcanza madurez con el patrón expect/actual, permitiendo compartir lógica de negocio entre Android e iOS manteniendo implementaciones nativas optimizadas - **Parámetros de contexto** evolucionan en 2.3.20 con detección de ambigüedades mejorada, requiriendo diseños de API más explícitos - **Coroutines y Flow** permanecen fundamentales, con distinción clara entre flujos fríos (evaluación lazy) y calientes (StateFlow, SharedFlow) - **Sealed interfaces** proporcionan modelado de estados type-safe con exhaustividad verificada en tiempo de compilación - **Funciones de alcance** y **seguridad ante nulos** demuestran dominio idiomático del lenguaje La preparación efectiva para entrevistas técnicas requiere no solo conocer estas características, sino comprender cuándo y por qué aplicar cada una en contextos de producción. --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/es/blog/android/kotlin-2-3-interview-questions