Il vous est peut-être un jour arrivé d’utiliser en Java le mot-clé instanceof
afin de vérifier dans votre code qu'une variable était bien d’un type (ou d’une classe) particulier, pour ensuite exécuter une action spécifique sur celle-ci. Prenons un exemple :
La méthode getDefaultSize()
ci-dessus est une méthode dont l’objectif est de retourner la taille d’une variable de type Object
(à savoir la superclasse de toutes les classes en Java) : ce paramètre pourra donc être n’importe quel objet Java.
Puis, grâce au mot-clé instanceof
, nous allons vérifier successivement si la variable est de type String
ou de type List
avant de la "cast" (ou de la "convertir") dans le type correspondant.
D’accord, j’avais compris cela tout seul ! Mais quel est le rapport avec Kotlin et ce chapitre ?
J’y viens ! Écrivons tout de suite la même méthode, mais en Kotlin.
Une conversion intelligente ?
private fun getDefaultSize(anyObject: Any): Int {
// Vérification du type
if (anyObject is String) {
return anyObject.length
// Vérification du type
} else if (anyObject is List<*>) {
return anyObject.size
}
return 0
}
Tiens, on remarque quelques changements en Kotlin… Pour commencer, le type Object
a disparu et a été remplacé par le type Any
. En Kotlin, toutes les classes ont pour superclasse la classe Any
! Puis, nous remarquons également que le mot-clé instanceof
a disparu, pour être remplacé par le mot-clé is
réalisant la même action.
Et pour terminer, on s'aperçoit que le cast... a disparu ! 😱
Impossible ! Sans le cast, une erreur à la compilation devrait apparaître, non ?
Eh non ! En fait en Kotlin, le cast est implicite avec le mot-clé is
: c’est ce que l’on appelle le Smart Cast (ou "transtypage intelligent", mais on va rester sur la version anglaise, hein ? ). Pas besoin donc de l’écrire !
On dit : merci qui ? Merci au compilateur Kotlin !
D’ailleurs, raccourcissons encore un peu plus cette fonction afin de la rendre Kotlin-friendly…
private fun getDefaultSize(anyObject: Any) = when (anyObject) {
is String -> anyObject.length
is List<*> -> anyObject.size
else -> 0
}
Super ! C’est tout de suite un peu plus propre et lisible, non ? Parfois, l’utilisation de la structure de contrôle when
vous permettra d’obtenir un résultat plus satisfaisant qu’avec une condition if
.
Convertissons-nous !
Un jour, il est probable que vous ayez besoin de convertir une variable dont vous ne connaissez pas forcément le type, en un autre type. Imaginons par exemple la situation suivante : vous avez une variable générique de type Any
, que vous souhaitez convertir (ou "cast") en une chaîne de caractères ( String
).
Pour effectuer cela en Kotlin, vous allez devoir utiliser le mot-clé as
:
val anyObject: Any = "Hello, Kotlin students!"
val message = anyObject as String
print(message)
Nous convertissons ici le contenu de la variable anyObject
en une variable de type String
grâce au mot-clé as
: ce type de conversion est appelé "Conversion non sécurisée" (ou "unsafe cast", en anglais).
Mais pourquoi ? Tout cela m’a l’air d’être parfaitement sécurisé ?
Pas du tout ! Imaginez que vous souhaitiez, au lieu de convertir le contenu de la variable anyObject
en String, la convertir plutôt en Int
? Eh bien, vous déclencherez une exception, et votre programme plantera…
En fait, le mot-clé as
est dit "non sécurisé", justement, car il renverra une exception de typeClassCastException
s'il n’arrive pas à réaliser la conversion. À vous donc de gérer (ou non) cette erreur dans votre code !
Pour cela, deux approches sont possibles :
La première approche est de simplement réaliser un try/catch
sur l’expression posant problème, et d'afficher un message d’erreur si l’exception est déclenchée :
val anyObject: Any = "Hello, Kotlin students!"
try{
val message = anyObject as Int
print(message)
} catch(exception: ClassCastException) {
print("Error!")
}
La seconde approche, quant à elle, est plus Kotlin-friendly. Elle va nous permettre de réaliser une "conversion sécurisée" (ou "safe cast", en anglais) grâce au mot-clé as
suivi d’un point d’interrogation ?
afin de dire explicitement au compilateur Kotlin que, si la conversion échoue, ce dernier devra affecter une valeur nulle à notre variable.
val anyObject: Any = "Hello, Kotlin students!"
val message: Int? = anyObject as? Int
print(message)
Plutôt efficace tout cela, non ?
Practice Makes Perfect!
La théorie, c'est bien, mais la pratique, c'est encore mieux ! Justement, nous vous avons concocté un petit exercice interactif de fin de chapitre pour appliquer toutes ces nouvelles connaissances.
🎓Un petit exercice, ça vous tente ? C'est par ici que ça se passe.
🎁Déjà terminé ? Le corrigé se trouve juste ici.
En résumé
En Kotlin, le mot-clé
instanceof
n’existe plus et est remplacé paris
.Le Smart Cast (ou "conversion intelligente") est la déduction automatique du type par le compilateur de Kotlin après une vérification avec
is
.Le Unsafe Cast (ou "conversion non sécurisée") est la tentative de conversion du type d’une variable en un autre grâce au mot-clé
as
. Si la tentative échoue, une erreur de typeClassCastException
sera déclenchée.Le Safe Cast (ou "conversion sécurisée") est la tentative de conversion du type d’une variable en un autre grâce au mot-clé
as
suivi du point d’interrogation?
. Si la tentative échoue, l'expression seranull
.
Pour aller plus loin :
KotlinLang : Type Checks
Vous maitrisez désormais le Smart Cast en Kotlin ! Dans le prochain chapitre, nous découvrirons comment gérer les exceptions.