La sécurité du null
Ce que tu vas apprendre
- Pourquoi
nullest dangereux et comment Kotlin t'en protège. - Utiliser
?,?.et?:pour gérer l'absence de valeur. - Savoir pourquoi éviter
!!.
Le problème de null
null signifie « aucune valeur ». Une recette peut ne pas avoir de photo, un ingrédient peut ne pas avoir de note.
Si ton code utilise une valeur absente comme si elle existait, le programme plante. Dans de nombreux langages, cela donne l'erreur NullPointerException.
Kotlin traite ce problème dès la compilation : il te force à dire si une valeur peut être absente.
Types nullables
var titre: String = "Tarte"
// titre = null // erreur de compilation
var photo: String? = "tarte.jpg"
photo = null // accepté
Un type normal, comme String, ne peut jamais contenir null. Le compilateur refuse l'affectation.
Un type nullable s'écrit avec un ? après le nom du type : String?. Il accepte une chaîne ou null.
Le safe call ?.
val photo: String? = null
val longueur = photo?.length
println(longueur) // null
Le safe call ?. appelle une propriété ou une fonction seulement si la valeur n'est pas null. Sinon, toute l'expression vaut null, sans plantage.
Le type de longueur est ici Int?, puisque le résultat peut être absent.
On peut chaîner plusieurs appels :
val pays = recette.auteur?.adresse?.pays
Dès qu'un maillon vaut null, le résultat entier vaut null.
L'opérateur Elvis ?:
val photo: String? = null
val longueur = photo?.length ?: 0
println(longueur) // 0
L'opérateur Elvis ?: donne une valeur de secours. Si la partie gauche n'est pas null, il la renvoie. Sinon, il renvoie la partie droite.
Le résultat est maintenant un Int simple, plus un Int?. Tu peux t'en servir sans autre précaution.
fun noteMoyenne(id: Int): Int = recetteParId(id)?.note ?: 0
Ce mélange de ?. et de ?: est le réflexe à prendre.
Tester avec if
Le compilateur suit tes vérifications.
fun afficher(photo: String?) {
if (photo != null) {
println(photo.length) // photo est traité comme String
}
}
Dans le bloc du if, Kotlin sait que photo n'est pas null. Tu n'as pas besoin de ?.. On appelle cela un cast automatique.
let : agir seulement si présent
val photo: String? = "tarte.jpg"
photo?.let { println("Photo : $it") }
?.let { ... } exécute le bloc uniquement si la valeur existe. À l'intérieur, it désigne cette valeur, désormais non nulle. Si photo vaut null, rien ne se passe.
Le cast sûr as?
val valeur: Any = "Gratin"
val nombre: Int? = valeur as? Int // null
val texte: String? = valeur as? String // "Gratin"
as? convertit une valeur vers un type. Si la conversion est impossible, il renvoie null au lieu de lever une erreur.
!! : à éviter
val photo: String? = null
val longueur = photo!!.length // NullPointerException
L'opérateur !! affirme « cette valeur n'est pas null ». Si elle l'est, le programme plante avec une NullPointerException. Tu retrouves alors le problème que Kotlin voulait éviter.
!! dans ton code. Préfère ?. avec ?:, un if, ou ?.let. Réserve !! aux rares cas où tu es certain que la valeur existe, et où un plantage serait préférable à une valeur par défaut.Quel outil choisir ?
| Besoin | Outil | Exemple |
|---|---|---|
| Autoriser l'absence | ? | String? |
| Lire sans planter | ?. | photo?.length |
| Une valeur de secours | ?: | photo?.length ?: 0 |
| Agir si présent | ?.let | photo?.let { ... } |
| Convertir sans erreur | as? | valeur as? Int |
À retenir
- Un type normal comme
Stringn'accepte jamaisnull, c'est vérifié à la compilation. String?est un type nullable : il accepte une chaîne ounull.?.appelle seulement si la valeur existe, sinon renvoienull.?:fournit une valeur de secours quand la partie gauche estnull.?.let { ... }exécute un bloc seulement si la valeur est présente.!!provoque uneNullPointerExceptionsi la valeur estnull: à éviter.
Pour aller plus loin
Sources officielles
Ensuite
Conditions, boucles et fonctions
Prendre des décisions avec if et when, répéter avec for, et regrouper du code dans des fonctions avec valeurs par défaut et arguments nommés.
Classes, data classes et objets
Modéliser tes données avec class et data class, puis utiliser object et companion object pour un singleton ou des fonctions de fabrique.
- Projet
- Lignes de code
- Niveau
- Le quartier
- Appartement
- Kotlin
- Pièce
- 3/7
- Plan n°
- kotlin/03.securite-du-null