# Kotlin 2.3 dla Androida: dekonstrukcja po nazwach, KMP i pytania rekrutacyjne 2026 > Pytania rekrutacyjne z Kotlin 2.3: dekonstrukcja po nazwach, Kotlin Multiplatform, parametry kontekstowe, korutyny i Flow. Przygotowanie do rozmów Android developera w 2026 z praktycznymi przykładami kodu. - Published: 2026-05-06 - Updated: 2026-05-17 - Author: SharpSkill - Tags: kotlin, android, interview, kmp, kotlin-multiplatform, coroutines - Reading time: 9 min --- Pytania rekrutacyjne dotyczące Kotlin 2.3 znalazły się w 2026 roku wśród najczęściej wyszukiwanych tematów dla stanowisk Android developera. Wraz z deklaracjami dekonstrukcji opartymi na nazwach, ustabilizowanymi parametrami kontekstowymi oraz dojrzałym ekosystemem Kotlin Multiplatform, rekruterzy oczekują od kandydatów biegłej znajomości tych funkcji. > **Co zmieniło się w Kotlin 2.3** > > Kotlin 2.3.20, wydany w marcu 2026, wprowadza deklaracje dekonstrukcji oparte na nazwach, zmiany w rozwiązywaniu przeciążeń dla parametrów kontekstowych oraz ulepszoną interoperacyjność KMP z C i TypeScript. Te funkcje pojawiają się często w rozmowach na stanowiska senior Android. ## Dekonstrukcja oparta na nazwach: najczęstsze pytanie rekrutacyjne z Kotlin 2.3 Przed wersją Kotlin 2.3 deklaracje dekonstrukcji opierały się na funkcjach `componentN()` zależnych od pozycji. Tworzyło to dobrze znaną pułapkę: zamiana kolejności właściwości w data class po cichu psuła istniejące miejsca dekonstrukcji. Klasyczne pytanie rekrutacyjne przedstawia ten scenariusz: ```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 rozwiązuje ten problem dzięki dekonstrukcji opartej na nazwach. Trzy tryby kompilatora kontrolują to zachowanie: ```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") } } ``` W trybie `complete` nawiasy okrągłe używają dopasowania po nazwach, a nawiasy kwadratowe zachowują zachowanie oparte na pozycji: ```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) } ``` Mocna odpowiedź podczas rozmowy wyjaśnia wszystkie trzy tryby i wskazuje, kiedy każdy z nich ma zastosowanie: `only-syntax` dla stopniowej migracji, `name-mismatch` do wychwytywania błędów w istniejącym kodzie oraz `complete` dla nowych projektów. ## Pytania rekrutacyjne o Kotlin Multiplatform dla Android developerów KMP wyszedł poza fazę eksperymentalną. Google oficjalnie wspiera go w dzieleniu logiki biznesowej między Androidem a iOS, a większość nowych projektów multi-platform domyślnie przyjmuje architekturę współdzielonego rdzenia. Typowe pytanie rekrutacyjne brzmi: „Jak ustrukturyzowałbyś moduł KMP dla wspólnej sieci?" ```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) } } } ``` Rekruterzy oceniają, czy kandydat rozumie mechanizm expect/actual, zależności specyficzne dla platform oraz granicę między kodem wspólnym a kodem platformy. Kolejne częste pytanie dotyczy [Swift Export](https://kotlinlang.org/docs/whatsnew2320.html), który znacznie ewoluował w 2026 roku. Funkcje suspend w Kotlinie mapują się teraz bezpośrednio na Swift async/await, a klasy zapieczętowane mapują się na enum Swift z wartościami powiązanymi. ## Parametry kontekstowe i zmiany w rozwiązywaniu przeciążeń Parametry kontekstowe zastępują przestarzałe API context receivers. Kotlin 2.3.20 wprowadził istotną zmianę w rozwiązywaniu przeciążeń: deklaracje z parametrami kontekstowymi nie są już traktowane jako bardziej szczegółowe niż te bez nich. ```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 } ``` Rekruterzy używają tego tematu, aby ocenić świadomość przełomowych zmian i strategii migracji. Kluczowy wniosek: poleganie na niejawnym rozwiązywaniu parametrów kontekstowych w celu przesłonięcia przeciążeń bez kontekstu już nie działa. ## Korutyny i Flow: nadal najważniejszy temat rozmów Android Pomimo nowych funkcji wprowadzonych w Kotlin 2.3, korutyny i Flow pozostają najczęściej testowanym obszarem. Pytania rekrutacyjne zwykle dotyczą różnicy między zimnymi a gorącymi flow, strukturalnej współbieżności oraz anulowania. ```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") } } ``` Uzupełniające pytanie często dotyczy bezpiecznego zbierania flow na Androidzie: ```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") } } } } ``` Strategia `WhileSubscribed(5000)` utrzymuje upstream aktywny przez 5 sekund po zniknięciu ostatniego subskrybenta, zapobiegając niepotrzebnym restartom podczas zmian konfiguracji, takich jak obrót ekranu. ## Sealed Classes i wyczerpujące when: pattern matching podczas rozmów Klasy zapieczętowane pojawiają się w niemal każdej rozmowie Android. Pytanie zwykle prosi kandydatów o zamodelowanie stanu interfejsu użytkownika: ```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 */ } )) } } ``` W Kotlinie wyrażenia `when` na typach zapieczętowanych są wyczerpujące w czasie kompilacji. Dodanie nowego podtypu wymusza jego obsługę wszędzie, co eliminuje całą kategorię błędów wykonania. Rekruterzy sprawdzają konkretnie, czy kandydat używa `sealed interface` (a nie `sealed class`) dla tego wzorca, ponieważ interfejsy pozwalają na bardziej elastyczne hierarchie. ## Kotlin/Wasm i międzyplatformowe cele kompilacji Kotlin/Wasm osiągnął status Beta i zapewnia wydajność zbliżoną do natywnej w przeglądarkach. Choć nie jest to jeszcze codzienna troska Android developerów, rekruterzy w firmach z produktami webowymi i mobilnymi pytają o niego. Kluczowe fakty na rozmowę: - Kotlin 2.3.20 dostarczył 4,6 razy szybszą interpolację stringów w Wasm dzięki JS String builtins - Rozmiary plików binarnych zmalały o około 5% - Clean buildy działają o 65% szybciej, buildy inkrementalne o 21% szybciej - Adnotacja `@nativeInvoke` pozwala obiektom Kotlin działać jako funkcje JavaScript Kotlin/JS zyskał również możliwość implementowania interfejsów Kotlin z TypeScript, usuwając wcześniejsze ograniczenie. W połączeniu ze wsparciem SWC dla transpilacji, Kotlin pokrywa teraz Androida, iOS (przez KMP), Web (przez Wasm/JS) i cele serwerowe z jednej bazy kodu. ## Funkcje scope: pozornie proste pytanie filtrujące podczas rozmów Funkcje scope (`let`, `run`, `with`, `apply`, `also`) wydają się proste, ale różnicują doświadczonych deweloperów Kotlin. Pytanie rekrutacyjne zwykle brzmi: „Kiedy używać `let` zamiast `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) } } ``` Framework decyzyjny: `apply` do konfiguracji obiektu (zwraca odbiorcę), `let` do przekształceń bezpiecznych dla null (zwraca wynik lambdy), `also` do efektów ubocznych (zwraca odbiorcę), `run` do obliczania wyniku w kontekście odbiorcy. ## Null safety i niebezpieczeństwo podwójnego wykrzyknika Null safety pozostaje fundamentalnym tematem rozmów. Pytanie „Dlaczego `!!` jest niebezpieczne?" sprawdza, czy kandydat naprawdę rozumie system typów Kotlina. ```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" } ``` Kompletna odpowiedź wspomina, że `!!` powinno pojawiać się tylko w kodzie testowym lub na granicach interop platformy, gdzie null jest naprawdę niemożliwy. ## Podsumowanie - Dekonstrukcja oparta na nazwach w Kotlin 2.3.20 eliminuje błędy zależne od pozycji. Warto znać wszystkie trzy tryby kompilatora: `only-syntax`, `name-mismatch`, `complete` - KMP jest stabilny produkcyjnie w 2026 roku. Spodziewaj się pytań o expect/actual, architekturę współdzielonego modułu i interop Swift Export - Parametry kontekstowe zastąpiły context receivers. Zmiana w rozwiązywaniu przeciążeń w 2.3.20 to typowe pytanie podchwytliwe - Korutyny i Flow dominują w rozmowach Android. Opanuj `StateFlow` vs `SharedFlow`, `WhileSubscribed` oraz strukturalną współbieżność - Sealed interface modelują stan UI z wyczerpującością na etapie kompilacji. Preferuj `sealed interface` zamiast `sealed class` - Funkcje scope wymagają jasnego frameworka decyzyjnego: odbiorca vs argument, wartość zwracana vs odbiorca - Null safety nie podlega negocjacji. Wyjaśnij, dlaczego `!!` podważa system typów i pokaż alternatywy --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/pl/blog/android/kotlin-2-3-interview-questions