[Kotlin] Nullabilité ?
par
, 31/08/2017 à 08h57 (1283 Affichages)
Amis programmeurs Kotlin, pour ceux qui auraient remarqué, désolé pour l'humour bidon
Les autres auront la possibilité de comprendre après avoir lu ce billet
Qu'est-ce qui différencie un type "nullable" d'un type standard ?
En java toute référence (donc non sur un type primitif) peut pointer
- soit sur un objet défini
- soit sur la valeur null
A ce propos : en Kotlin, il n'y a pas la notion de type primitif et de wrapper. Par défaut, un Int est converti vers une type primitif pour des raisons de performances, et sinon dans un type java.lang.Integer quand cela n'est pas possible pour le compilateur.
Cependant en Kotlin, une distinction très importante et utile est faite par le compilateur entre un type qui peut valoir null, et un type qui n'acceptera jamais la valeur null.
Illustration avec le snippet suivant :
Ainsi un type nullable se déclare avec le type de base auquel on ajoute le symbole '?'.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 val age:Int = 10 // ok val age:Int = null // erreur de compilation !!! (A) val adresse:String? = "Saint-Germain en Laye" // Besoin de commenter ? (B) val adresse:String? = null // Ok, ca passe sans problème
Alors, que se passe-t-il si je veux accéder à la longueur de la chaîne adresse ci-dessus ? Et bien, surprise (ou non), mais dans l'extrait (A) tout comme l'extrait (B), il y aura une erreur de compilation ! Avouez que cela est bien utile pour éviter bien des écueils
Mais alors, comment malgré tout accéder à la longueur "au moins" -vous comprendrez plus tard dans ce billet" - dans le cas (A) , où l'on sait pourtant plus que le compilateur et on est sûr que la valeur n'est pas null ?
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 val adresse:String? = "Saint-Germain en Laye" println(adresse.length) // erreur de compilation !!! Impossible d'accéder à la propriété length car adresse est nullable !
C'est justement l'objectif de la section suivante, mais juste à titre d'exemple, on pourrait écrire
L'utilisation d'un type nullable
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 val adresse:String? = "Saint-Germain en Laye" if (adresse != null) println(adresse.length)
Comme nous l'avons vu plus haut, la structure de contrôle if permet d'utiliser simplement une valeur nullable :
Question d'observation : avez-vous remarqué l'utilisation de la variable adresse sans avoir effectué aucun casting de String? vers String ? Ici on a une nouvelle application de la notion de Smart-Cast, tel que décrit dans un précédent billet.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 val adresse:String? = "Saint-Germain en Laye" if (adresse != null) println(adresse.length)
Toutefois cela ne peut fonctionner avec le mot-clé when : cette structure de contrôle n'acceptant que des comparaison de valeurs (sans "is") ou de type (avec "is", comme vu précédemment dans la section casting de types) : à moins de s'embêter à vérifier les deux types, à savoir nullable et non nullable. Mais quel en serait l'intérêt?
Sinon il y a un moyen beacoup plus simple de s'y prendre, qui combine deux syntaxes n'existant pas en Java :
- l'acces à une propriété nullable (.?)
- l'opérateur Elvis (?
Avec l'accès à une propriété nullable :
Ainsi, pour la variable monNull, monNull?.length retourne null, sans provoquer d'exception, et l'instruction associée (à savoir println) n'est pas exécutée.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 val monNullable: String? = "12345" val monNull: String? = null println(monNullable?.length) // affiche 5 println(monNull?.length) // n'affiche rien !!!
On aurait pu aussi afficher une valeur par défaut, une valeur de substitution pour ce cas précis. En effet, Kotlin reconnaît l'opérateur elvis (?:
Voilà, j'espère que vous aurez pris plaisir à lire ce billet
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 val monNullable: String? = "12345" val monNull: String? = null println(monNullable?.length ?: 0) // affiche 5 println(monNull?.length ?: 0) // affiche 0![]()