Kotlin 2.3 pour Android : Destructuration par Nom, KMP et Questions d'Entretien 2026

Questions d'entretien Kotlin 2.3 pour développeurs Android en 2026. Destructuration par nom, KMP, paramètres de contexte, Flow et coroutines avec exemples de code.

Kotlin 2.3 pour Android questions d'entretien 2026

Kotlin 2.3 marque une etape importante dans l'evolution du langage pour le developpement Android. Cette version introduit la destructuration par nom, une fonctionnalite qui elimine une source frequente de bugs subtils dans les bases de code existantes. Les developpeurs Android qui preparent des entretiens techniques en 2026 doivent maitriser ces nouveautes, ainsi que les patterns Kotlin Multiplatform (KMP) et les bonnes pratiques autour des coroutines et des Flows.

Ce qui change avec Kotlin 2.3

La destructuration par nom permet de faire correspondre les variables aux proprietes par leur nom plutot que par leur position. Les parametres de contexte sortent de la phase experimentale avec de nouvelles regles de resolution. Kotlin Multiplatform devient le standard recommande pour le partage de code entre Android et iOS.

La destructuration par nom : resolution d'un probleme historique

Avant Kotlin 2.3, la destructuration des data classes reposait uniquement sur la position des composants. Cette approche, bien que simple, creait des bugs difficiles a detecter lors de la refactorisation du code.

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!
}

Ce code compile sans erreur, mais produit un resultat incorrect. Le developpeur a nomme ses variables email et username, mais la destructuration ignore ces noms et utilise les positions component1() et component2(). Ce type de bug survient frequemment lors du renommage ou de la reordonnation des proprietes d'une data class.

Kotlin 2.3 introduit trois modes de compilation pour gerer cette transition progressivement.

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")
    }
}

Le mode only-syntax active uniquement la nouvelle syntaxe explicite. Le mode name-mismatch emet des avertissements lorsque les noms de variables ne correspondent pas aux proprietes. Le mode complete active la destructuration par nom par defaut.

Avec le mode complet active, le meme code produit maintenant le resultat attendu.

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)
}

La nouvelle syntaxe avec crochets [first, second] preserve le comportement positionnel pour les cas ou il reste necessaire. Cette distinction claire entre les deux approches elimine toute ambiguite.

Kotlin Multiplatform : partage de code Android et iOS

Kotlin Multiplatform (KMP) atteint un niveau de maturite qui en fait le choix recommande par Google pour partager la logique metier entre Android et iOS. Les entretiens techniques en 2026 evaluent frequemment la comprehension du pattern expect/actual.

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())
    }
}

Ce code reside dans le module commonMain et compile pour toutes les plateformes cibles. La declaration expect indique qu'une implementation specifique a chaque plateforme doit fournir la fonction createHttpClient().

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)
        }
    }
}

L'implementation Android utilise OkHttp, le moteur HTTP standard de la plateforme. Une implementation equivalente pour iOS utiliserait le moteur Darwin. Ce pattern permet de beneficier des optimisations natives de chaque plateforme tout en partageant la logique de serialisation et de gestion des erreurs.

Parametres de contexte : nouvelles regles en 2.3.20

Les parametres de contexte, introduits experimentalement dans les versions precedentes, evoluent avec de nouvelles regles de resolution des ambiguites dans Kotlin 2.3.20.

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
}

Cette modification vise a rendre le code plus explicite et a eviter les comportements surprenants lors de la resolution des surcharges. Les developpeurs doivent renommer ou qualifier explicitement les variantes contextuelles pour lever l'ambiguite.

Flow et StateFlow : gestion des flux de donnees reactifs

La comprehension des Flows constitue un prerequis pour tout developpeur Android moderne. Les entretiens techniques distinguent systematiquement les Cold Flows des Hot Flows.

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")
    }
}

Un Cold Flow ne s'execute que lorsqu'un collecteur s'y abonne. Chaque collecteur declenche une nouvelle execution du bloc flow. Un Hot Flow, en revanche, emet des valeurs independamment des collecteurs. Le StateFlow conserve toujours la derniere valeur emise, tandis que le SharedFlow peut emettre des evenements ponctuels sans valeur initiale.

L'integration avec le ViewModel suit un pattern etabli qui garantit la gestion correcte du cycle de vie.

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")
            }
        }
    }
}

L'operateur stateIn convertit un Flow froid en StateFlow chaud. Le parametre WhileSubscribed(5000) maintient le Flow actif pendant 5 secondes apres le dernier collecteur, ce qui gere elegamment les rotations d'ecran sans redemarrer le Flow inutilement.

Prêt à réussir tes entretiens Android ?

Entraîne-toi avec nos simulateurs interactifs, fiches express et tests techniques.

Modelisation des etats avec sealed interface

Les sealed interfaces representent le pattern recommande pour modeliser les etats d'une interface utilisateur. Ce pattern garantit l'exhaustivite des verifications lors de la compilation.

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 */ }
        ))
    }
}

L'utilisation de sealed interface plutot que sealed class permet aux sous-types d'heriter d'autres classes si necessaire. Le modificateur out sur le parametre de type T assure la covariance, permettant d'utiliser UiState<Nothing> la ou UiState<T> est attendu.

Fonctions de portee : apply, let, also, run

Les fonctions de portee Kotlin simplifient les operations courantes sur les objets. Leur maitrise distingue les developpeurs experimentes lors des revues de code et des entretiens.

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)
    }
}

La fonction apply configure un objet et le retourne, ideale pour les builders. La fonction let transforme une valeur nullable et retourne le resultat de la lambda. La fonction also execute des effets de bord tout en retournant l'objet original, utile pour le logging. La fonction run execute un bloc avec un recepteur et retourne le resultat.

Null safety : patterns et anti-patterns

La gestion des valeurs nullables constitue un pilier de Kotlin. Les entretiens evaluent la capacite a eviter les patterns dangereux tout en ecrivant du code concis.

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"
}

L'operateur !! contourne le systeme de null safety et devrait etre evite dans la quasi-totalite des cas. L'operateur Elvis ?: combine avec run ou return offre une gestion elegante des cas null. Cette approche rend le code plus robuste et son intention plus claire.

Passe à la pratique !

Teste tes connaissances avec nos simulateurs d'entretien et tests techniques.

Conclusion

Kotlin 2.3 apporte des ameliorations significatives pour le developpement Android moderne. Les points essentiels a retenir pour les entretiens techniques en 2026 incluent :

  • Destructuration par nom : comprendre la difference entre la correspondance par position et par nom, savoir configurer les modes de compilation et utiliser la syntaxe avec crochets pour forcer le comportement positionnel
  • Kotlin Multiplatform : maitriser le pattern expect/actual, structurer les modules commonMain et platformMain, utiliser Ktor pour les appels reseau partages
  • Parametres de contexte : connaitre les nouvelles regles de resolution des ambiguites en 2.3.20 et savoir les contourner
  • Flows et coroutines : distinguer Cold Flow et Hot Flow, utiliser StateFlow pour l'etat et SharedFlow pour les evenements, appliquer correctement stateIn avec WhileSubscribed
  • Sealed interfaces : modeliser les etats UI de maniere exhaustive, utiliser la covariance avec le modificateur out
  • Fonctions de portee : choisir la fonction appropriee selon le contexte (apply pour configuration, let pour transformation, also pour logging, run pour execution)
  • Null safety : eviter l'operateur !!, privilegier l'operateur Elvis et les smart casts

Ces competences constituent le socle attendu des developpeurs Android seniors et sont systematiquement evaluees lors des processus de recrutement en 2026.

Passe à la pratique !

Teste tes connaissances avec nos simulateurs d'entretien et tests techniques.

Tags

#kotlin
#android
#entretien
#kmp
#coroutines

Partager

Articles similaires