# Kotlin 2.3 Android面接対策:名前ベースの分割代入、KMP、頻出質問を徹底解説【2026年版】 > 2026年のAndroid開発者面接で問われるKotlin 2.3の新機能を網羅的に解説。名前ベースの分割代入、Kotlin Multiplatform、コンテキストパラメータ、Flowとコルーチンのコード例付き。 - Published: 2026-05-06 - Updated: 2026-05-06 - Author: SharpSkill - Tags: kotlin, android, interview, kotlin-multiplatform, coroutines - Reading time: 12 min --- 2026年現在、Kotlin 2.3の面接対策はAndroid開発者にとって最重要テーマの一つとなっている。名前ベースの分割代入宣言、安定化されたコンテキストパラメータ、そして成熟したKotlin Multiplatformエコシステムなど、面接官はこれらの新機能に対する深い理解を求めている。 > **Kotlin 2.3の主な変更点** > > 2026年3月にリリースされたKotlin 2.3.20では、名前ベースの分割代入宣言、コンテキストパラメータのオーバーロード解決の変更、C・TypeScriptとのKMP相互運用性の向上が導入された。これらの機能はシニアAndroid面接で頻繁に出題される。 ## 名前ベースの分割代入:Kotlin 2.3で最も出題される面接問題 Kotlin 2.3以前、分割代入宣言は位置ベースの`componentN()`関数に依存していた。これにより、データクラスのプロパティ順序を変更すると、既存の分割代入箇所が暗黙的に破壊されるという有名な落とし穴が存在していた。 典型的な面接問題は、次のシナリオを提示する: ```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では、名前ベースの分割代入によってこの問題が解決された。コンパイラには3つのモードが用意されている: ```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) } ``` 面接で高い評価を得る回答は、3つのモード全てを説明し、それぞれの適用場面を明確にする。`only-syntax`は段階的な移行に、`name-mismatch`は既存コードのバグ検出に、`complete`は新規プロジェクトに適している。 ## Android開発者向けKotlin Multiplatform面接問題 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年にはSwift Exportが大幅に進化し、Kotlinのsuspend関数がSwiftのasync/awaitに直接マッピングされ、sealed classがSwiftの関連値付きenumにマッピングされるようになった。 ## コンテキストパラメータとオーバーロード解決の変更 コンテキストパラメータは、非推奨となったコンテキストレシーバーAPIを置き換えるものである。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でFlowを安全に収集する方法が問われることが多い: ```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)`戦略は、最後のサブスクライバーが消えた後も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では、sealed型に対する`when`式はコンパイル時に網羅性が検証される。新しいサブタイプを追加すると、全てのwhen式で処理が強制されるため、ランタイムバグの一カテゴリ全体が排除される。面接官は特に、このパターンで`sealed class`ではなく`sealed interface`を使用するかどうかを確認する。インターフェースの方がより柔軟な階層構造を実現できるためである。 ## Kotlin/Wasmとクロスプラットフォームコンパイルターゲット Kotlin/WasmはBetaステータスに到達し、ブラウザでネイティブに近いパフォーマンスを実現している。Android開発者の日常業務では直接的に関わる場面は少ないが、Web+モバイル製品を扱う企業の面接では問われることがある。 面接で押さえるべきポイント: - Kotlin 2.3.20ではJS String builtinsを通じてWasmでの文字列補間が4.6倍高速化 - バイナリサイズが約5%削減 - クリーンビルドが65%高速化、インクリメンタルビルドが21%高速化 - `@nativeInvoke`アノテーションによりKotlinオブジェクトをJavaScript関数として動作させることが可能 Kotlin/JSでも、TypeScriptからKotlinインターフェースを実装する機能が追加され、以前の制限が解消された。SWCによるトランスパイルサポートと合わせて、Kotlinは単一コードベースからAndroid、iOS(KMP経由)、Web(Wasm/JS経由)、サーバーサイドの全ターゲットをカバーできるようになっている。 ## スコープ関数:見た目以上に差がつく面接のフィルター問題 スコープ関数(`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" } ``` 完全な回答では、`!!`はテストコードやプラットフォーム相互運用の境界など、nullが絶対に発生しない場面でのみ使用すべきであると言及する。 ## まとめ - Kotlin 2.3.20の名前ベースの分割代入は、位置依存のバグを排除する。3つのコンパイラモード(`only-syntax`、`name-mismatch`、`complete`)を理解しておくことが重要である - KMPは2026年に本番運用レベルで安定している。expect/actual、共有モジュールアーキテクチャ、Swift Exportの相互運用に関する質問が想定される - コンテキストパラメータはコンテキストレシーバーを置き換えた。2.3.20でのオーバーロード解決の変更は、頻出のひっかけ問題である - コルーチンとFlowはAndroid面接を支配している。`StateFlow`対`SharedFlow`、`WhileSubscribed`、構造化された並行性を習得すべきである - Sealedインターフェースはコンパイル時の網羅性チェックを伴うUI状態モデリングに適している。`sealed class`よりも`sealed interface`が推奨される - スコープ関数には明確な判断基準が必要である:レシーバーか引数か、戻り値かレシーバーか - Null安全性は妥協できない項目である。`!!`が型システムを損なう理由を説明し、代替手段を示すことが求められる --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/ja/blog/android/kotlin-2-3-interview-questions