# Kotlin 2.3 для Android: іменована деструктуризація, KMP та співбесідні питання 2026 > Питання на співбесіду з Kotlin 2.3, що охоплюють іменовану деструктуризацію, Kotlin Multiplatform, контекстні параметри, корутини та Flow. Підготовка до співбесід Android-розробника у 2026 з реальними прикладами коду. - Published: 2026-05-06 - Updated: 2026-05-17 - Author: SharpSkill - Tags: kotlin, android, interview, kmp, kotlin-multiplatform, coroutines - Reading time: 9 min --- Питання на співбесіду з Kotlin 2.3 у 2026 році увійшли до числа найбільш популярних тем для позицій Android-розробника. Завдяки оголошенням іменованої деструктуризації, стабілізованим контекстним параметрам та зрілій екосистемі Kotlin Multiplatform інтерв'юери очікують від кандидатів вільного володіння цими можливостями. > **Що змінилося в Kotlin 2.3** > > Kotlin 2.3.20, випущений у березні 2026, представляє оголошення деструктуризації за іменами, зміни у розв'язанні перевантажень для контекстних параметрів та покращену взаємодію KMP із C та TypeScript. Ці можливості часто з'являються на співбесідах для senior Android. ## Іменована деструктуризація: найпоширеніше питання на співбесіду з Kotlin 2.3 До Kotlin 2.3 оголошення деструктуризації покладалися на позиційні функції `componentN()`. Це створювало добре відому пастку: зміна порядку властивостей у data class тихо порушувала існуючі місця деструктуризації. Класичне питання на співбесіду подає такий сценарій: ```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! } ``` Kotlin 2.3.20 вирішує цю проблему за допомогою деструктуризації за іменами. Поведінкою керують три режими компілятора: ```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") } } ``` У режимі `complete` круглі дужки використовують зіставлення за іменами, а квадратні дужки зберігають позиційну поведінку: ```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) } ``` Сильна відповідь на співбесіді пояснює всі три режими та визначає, коли кожен застосовується: `only-syntax` для поступової міграції, `name-mismatch` для виявлення помилок у наявному коді та `complete` для нових проєктів. ## Питання на співбесіду з Kotlin Multiplatform для Android-розробників KMP перейшов з експериментальної фази. Google офіційно підтримує його для спільного використання бізнес-логіки між Android та iOS, а більшість нових мультиплатформових проєктів за замовчуванням приймають архітектуру спільного ядра. Типове питання на співбесіду: «Як би ви структурували KMP-модуль для спільної мережевої взаємодії?» ```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()) } } ``` ```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) } } } ``` Інтерв'юери оцінюють, чи розуміє кандидат механізм expect/actual, специфічні для платформи залежності та межу між спільним та платформним кодом. Інше часте питання стосується [Swift Export](https://kotlinlang.org/docs/whatsnew2320.html), який значно розвинувся у 2026 році. Suspend-функції Kotlin тепер відображаються безпосередньо на Swift async/await, а sealed-класи — на Swift enum з пов'язаними значеннями. ## Контекстні параметри та зміни у розв'язанні перевантажень Контекстні параметри замінюють застаріле API context receivers. Kotlin 2.3.20 вніс критичну зміну у розв'язання перевантажень: оголошення з контекстними параметрами більше не розглядаються як специфічніші за ті, що їх не мають. ```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 } ``` Інтерв'юери використовують цю тему, щоб оцінити обізнаність із критичними змінами та стратегіями міграції. Ключовий висновок: розраховувати на неявне розв'язання контекстних параметрів для перевантажень без контексту вже не вдасться. ## Корутини та Flow: досі головна тема Android-співбесід Попри нові можливості Kotlin 2.3, корутини та Flow залишаються найбільш тестованою областю. Питання на співбесіду зазвичай зондують різницю між холодними та гарячими потоками, структуровану конкурентність та скасування. ```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") } } ``` Уточнююче питання часто стосується безпечного збору потоків в Android: ```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") } } } } ``` Стратегія `WhileSubscribed(5000)` тримає upstream активним протягом 5 секунд після зникнення останнього підписника, що запобігає непотрібним перезапускам під час змін конфігурації, як-от обертання екрана. ## Sealed-класи та вичерпний when: зіставлення зразків на співбесідах Sealed-класи з'являються майже на кожній Android-співбесіді. Питання зазвичай просить кандидатів змоделювати стан UI: ```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 */ } )) } } ``` У Kotlin вирази `when` над sealed-типами є вичерпними під час компіляції. Додавання нового підтипу змушує обробляти його всюди, що усуває цілу категорію помилок виконання. Інтерв'юери особливо перевіряють, чи кандидат використовує `sealed interface` (а не `sealed class`) для цього патерну, оскільки інтерфейси дозволяють гнучкіші ієрархії. ## Kotlin/Wasm та крос-платформові цілі компіляції Kotlin/Wasm досяг статусу Beta та забезпечує продуктивність, близьку до нативної, у браузерах. Хоча це поки не щоденна турбота Android-розробників, інтерв'юери у компаніях із web+mobile продуктами питають про нього. Ключові факти для співбесіди: - Kotlin 2.3.20 забезпечив у 4,6 рази швидшу інтерполяцію рядків у Wasm завдяки JS String builtins - Розміри бінарних файлів зменшилися приблизно на 5% - Чисті збірки виконуються на 65% швидше, інкрементальні — на 21% швидше - Анотація `@nativeInvoke` дозволяє об'єктам Kotlin діяти як функції JavaScript Kotlin/JS також отримав можливість реалізовувати Kotlin-інтерфейси з TypeScript, усунувши попереднє обмеження. У поєднанні з підтримкою SWC для транспіляції Kotlin тепер охоплює Android, iOS (через KMP), Web (через Wasm/JS) та серверні цілі з єдиної кодової бази. ## Scope-функції: оманливо просте питання-фільтр на співбесіді Scope-функції (`let`, `run`, `with`, `apply`, `also`) виглядають простими, але відрізняють досвідчених Kotlin-розробників. Питання на співбесіду зазвичай звучить так: «Коли використовувати `let` проти `apply`?» ```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) } } ``` Фреймворк прийняття рішень: `apply` для конфігурації об'єкта (повертає одержувача), `let` для null-безпечних перетворень (повертає результат лямбди), `also` для побічних ефектів (повертає одержувача), `run` для обчислення результату у контексті одержувача. ## Null-безпека та небезпека подвійного знака оклику Null-безпека залишається фундаментальною темою співбесід. Питання «Чому `!!` небезпечний?» перевіряє, чи дійсно кандидат розуміє систему типів Kotlin. ```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" } ``` Повна відповідь зазначає, що `!!` має з'являтися лише в тестовому коді або на межах платформного interop, де null справді неможливий. ## Висновок - Іменована деструктуризація в Kotlin 2.3.20 усуває позиційно залежні помилки. Варто знати всі три режими компілятора: `only-syntax`, `name-mismatch`, `complete` - KMP стабільний для продакшну у 2026. Очікуйте питань про expect/actual, архітектуру спільного модуля та взаємодію Swift Export - Контекстні параметри замінили context receivers. Зміна у розв'язанні перевантажень у 2.3.20 — поширене каверзне питання - Корутини та Flow домінують на Android-співбесідах. Опануйте `StateFlow` проти `SharedFlow`, `WhileSubscribed` та структуровану конкурентність - Sealed-інтерфейси моделюють стан UI з вичерпністю на етапі компіляції. Надавайте перевагу `sealed interface` над `sealed class` - Scope-функції потребують чіткого фреймворку рішень: одержувач проти аргументу, повернене значення проти одержувача - Null-безпека не підлягає обговоренню. Поясніть, чому `!!` підриває систему типів, і продемонструйте альтернативи --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/uk/blog/android/kotlin-2-3-interview-questions