Kotlin 2.3 : 5 nouveautés vraiment utiles (et quoi activer tout de suite)

Publish date: 23 Jan 2026
Tags: kotlin jvm multiplatform kmp wasm tooling

Kotlin 2.3.0 est une release de maturité : moins de “features tape-à-l’œil”, plus de garde-fous, de DX et de perf. Elle ne “change pas votre façon de coder” par magie — mais elle vous évite des classes entières de bugs et réduit du boilerplate si vous activez les bons interrupteurs. :contentReference[oaicite:0]{index=0}

TL;DR #


1) Moins de bugs “silencieux” : le unused return value checker (opt-in) #

Le problème #

En Kotlin (comme ailleurs), il est facile d’écrire une expression qui produit une valeur… puis de l’abandonner. Ça arrive dans des branches if, des appels de fonctions “transformantes”, ou des chaînes de traitement où vous pensiez muter mais vous avez en fait créé une nouvelle valeur.

Kotlin 2.3.0 introduit un vérificateur qui peut avertir quand une expression retourne une valeur (autre que Unit/Nothing) et que cette valeur n’est pas utilisée. :contentReference[oaicite:6]{index=6}

Exemple typique #

Bug classique : une branche “fabrique” une chaîne, mais ne la retourne pas (et le code continue sur un chemin qui suppose une autre forme de name).

fun formatGreeting(name: String): String {
  if (name.isBlank()) return "Hello, anonymous user!"

  if (!name.contains(' ')) {
    // Warning Kotlin 2.3 (si checker activé) : résultat ignoré
    "Hello, " + name.replaceFirstChar(Char::titlecase) + "!"
  }

  val (first, last) = name.split(' ') // <- si pas d'espace, destructuring = crash
  return "Hello, $first! Or should I call you Dr. $last?"
}

Ce n’est pas split() qui “explose” : c’est le destructuring qui échoue parce que la liste n’a pas 2 éléments. Le checker vous met le nez sur la branche fautive au moment de compiler.

Activation (et stratégie réaliste) #

Le checker est désactivé par défaut. (Kotlin)

Gradle (Kotlin DSL) :

kotlin {
  compilerOptions {
    freeCompilerArgs.add("-Xreturn-value-checker=check")
  }
}

Marquer vos API (le vrai levier) #

En mode check, Kotlin remonte surtout des warnings pour les fonctions “marquées”. Vous pouvez marquer les vôtres avec @MustUseReturnValues (à l’échelle fichier / classe / fonction). (Kotlin)

Et pour les cas où ignorer est normal (ex: add()), vous pouvez annoter avec @IgnorableReturnValue. (Kotlin)

Supprimer localement (quand ignorer est volontaire) #

Assignation à la variable spéciale _ :

val _ = computeValue()

C’est explicitement documenté comme mécanisme de suppression. (Kotlin)


2) Fin du pattern _state : Explicit Backing Fields (expérimental) #

Le problème #

Le pattern “propriété publique read-only + backing privé mutable” est omniprésent (Flow/StateFlow, listes exposées en List mais stockées en MutableList, etc.). Jusqu’ici, vous deviez entretenir deux propriétés (et deux noms).

Avant :

private val _city = MutableStateFlow("")
val city: StateFlow<String> get() = _city

fun updateCity(newCity: String) { _city.value = newCity }

Après Kotlin 2.3.0 (expérimental) :

val city: StateFlow<String>
  field = MutableStateFlow("")

fun updateCity(newCity: String) {
  // smart-cast : city est vu comme le type du field dans la portée privée
  city.value = newCity
}

Cette syntaxe réduit le boilerplate et vous évite la gymnastique _x/x. Le point clé : le compilateur peut faire un smart-cast vers le type du field dans la portée “privée” de la déclaration. (Kotlin)

Activation #

C’est Experimental et ça demande un flag :

kotlin {
  compilerOptions {
    freeCompilerArgs.add("-Xexplicit-backing-fields")
  }
}

(Kotlin)

Quand l’utiliser (et quand éviter) #


3) Stdlib : UUID v7 (triables) + parseOrNull() (sans exceptions) #

L’API UUID de la stdlib reste expérimentale (annotation @ExperimentalUuidApi), mais Kotlin 2.3.0 l’améliore nettement : (Kotlin)

Pourquoi v7 est intéressant en base #

Un UUID v7 encode un timestamp (en ms) dans son préfixe, ce qui donne des identifiants globalement ordonnables (très utile pour les index et l’insertion “en fin”). (Kotlin)

Deux mises en garde (à ne pas ignorer) #


4) Kotlin/Native : Swift export plus idiomatique + builds release plus rapides #

Si vous faites du KMP iOS, Kotlin 2.3.0 améliore l’interop via Swift export :

Côté perf : les tâches release linkRelease* (ex: linkReleaseFrameworkIosArm64) peuvent être jusqu’à ~40% plus rapides selon la taille du projet. (Kotlin)

⚠️ Swift export est Experimental et pas présenté comme “ready prod” dans la doc dédiée. (Kotlin)


5) Kotlin/Wasm : binaires plus légers + qualifiedName par défaut #

Kotlin 2.3.0 active par défaut les fully qualified names côté Wasm (donc KClass.qualifiedName sans config), sans gonfler le binaire grâce à une optimisation de stockage des chaînes. (Kotlin)

Le détail qui compte :

Résultat annoncé :


Bonus : ce qui passe “Stable” en 2.3.0 #

Deux éléments qui changent la vie… parce qu’ils deviennent fiables/standard :


Plan d’action concret (sans se raconter d’histoires) #

  1. Passez à Kotlin 2.3.0, puis activez uniquement -Xreturn-value-checker=check en premier (pas full). (Kotlin)
  2. Ajoutez @MustUseReturnValues sur vos API critiques (celles où ignorer le retour est un bug), et @IgnorableReturnValue là où ignorer est normal. (Kotlin)
  3. Si votre équipe accepte l’expérimental : testez -Xexplicit-backing-fields sur un module “safe” (ex: UI/state) pour supprimer le pattern _x. (Kotlin)
  4. Si vous stockez des UUID en clé primaire : regardez Uuid.generateV7() (mais assumez la fuite de timestamp). (Kotlin)
  5. Si vous livrez du Wasm : upgrade, c’est du gain “gratuit” côté taille et introspection runtime. (Kotlin)

Checklist de sortie (signaux observables) #


Références #