126 votes

Que fait ?: en Kotlin? (Opérateur Elvis)

Je ne peux pas comprendre ce que ?: fait dans, par exemple, ce cas:

val list = mutableList ?: mutableListOf() 

et pourquoi peut-il être modifié en ceci:

val list = if (mutableList != null) mutableList else mutableListOf()

10 votes

Retournez le côté gauche s'il n'est pas nul, sinon retournez le côté droit. La première expression est une courte notation de la deuxième expression. kotlinlang.org/docs/reference/null-safety.html#elvis-operato‌​r

146voto

s1m0nw1 Points 21698

TL;DR: Si la référence d'objet résultante [premier opérande] n'est pas null, elle est renvoyée. Sinon, la valeur du deuxième opérande (qui peut être null) est renvoyée. De plus, l'opérateur peut envoyer une exception si null est renvoyé.


L'opérateur Elvis fait partie de nombreux langages de programmation, par exemple Kotlin mais aussi Groovy ou C#. Je trouve la définition de Wikipedia assez précise :

Dans certains langages de programmation informatique, l'opérateur Elvis ?: est un opérateur binaire qui renvoie son premier opérande si cet opérande est true, et évalue sinon et renvoie son deuxième opérande. C'est une variante de l'opérateur conditionnel ternaire, ? :, trouvé dans ces langages (et beaucoup d'autres) : l'opérateur Elvis est l'opérateur ternaire avec son deuxième opérande omis.

Ce qui suit est particulièrement vrai pour Kotlin :

Certains langages de programmation informatique ont des sémantiques différentes pour cet opérateur. Au lieu que le premier opérande doive résulter en un booléen, il doit résulter en une référence d'objet. Si la référence d'objet résultante n'est pas null, elle est renvoyée. Sinon, la valeur du deuxième opérande (qui peut être null) est renvoyée. Si le deuxième opérande est null, l'opérateur peut également envoyer une exception.

Un exemple :

x ?: y // renvoie `x` si `x` n'est pas null, `y` sinon.
x ?: throw SomeException() // renvoie `x` si `x` n'est pas null, envoie SomeException sinon

105voto

Kerooker Points 1740

L'opérateur Elvis est représenté par un point d'interrogation suivi de deux points : ?: et peut être utilisé avec cette syntaxe :

premier opérande ?: deuxième opérande

Cela vous permet d'écrire un code concis, et fonctionne comme suit :

Si le premier opérande n'est pas null, alors il sera retourné. S'il est null, alors le deuxième opérande sera retourné. Cela peut être utilisé pour garantir qu'une expression ne retournera pas de valeur nulle, car vous fournirez une valeur non nullable si la valeur fournie est nulle.


Par exemple (en Kotlin) :

fun retrieveString(): String {    //Remarquez que ce type n'est pas nullable
    val variableNulle: String? = getPotentialNull() //Cette variable peut être nulle

    return variableNulle ?: "Seconde Chaîne Non-Null"
}

Dans ce cas, si la valeur calculée de getPotentialNull n'est pas nulle, elle sera retournée par retrieveString; si elle est nulle, la seconde expression "Seconde Chaîne Non-Null" sera retournée à la place.

Notez également que l'expression du côté droit est évaluée uniquement si le côté gauche est null.

En Kotlin, vous pourriez utiliser n'importe quelle expression en tant que deuxième opérande, telle qu'une expression throw Exception

return variableNulle ?: throw IllegalResponseException("Ma fonction interne a retourné null ! Oh non !")

Le nom Elvis Operator vient du célèbre chanteur américain Elvis Presley. Sa coiffure ressemble à un point d'interrogation

Elvis Point d'Interrogation

Source : Wojda, I. Moskala, M. Android Development with Kotlin. 2017. Packt Publishing

43voto

zsmb13 Points 36441

Cela s'appelle l'opérateur Elvis et il fait... Exactement ce que vous avez décrit dans votre question. Si son côté gauche est une valeur null, il renvoie plutôt le côté droit, un peu comme une solution de secours. Sinon, il renvoie simplement la valeur du côté gauche.

a ?: b est simplement un raccourci pour if (a != null) a else b.

Quelques exemples supplémentaires avec des types:

val x: String? = "foo"
val y: String = x ?: "bar"      // "foo", car x était non-nul    

val a: String? = null
val b: String = a ?: "bar"      // "bar", car a était null

15 votes

Si vous venez de Java, c'est plutôt un raccourci pour : a != null ? a : b

10voto

Willi Mentzel Points 7681

Jetons un coup d'œil à la définition :

Lorsque nous avons une référence nullable r, nous pouvons dire "si r n'est pas null, l'utiliser, sinon utiliser une valeur non nulle x" :

L'opérateur ?: (Elvis) évite la verbeosité et rend votre code vraiment concis.

Par exemple, de nombreuses fonctions d'extension de collection retournent null comme valeur de repli.

listOf(1, 2, 3).firstOrNull { it == 4 } ?: throw IllegalStateException("Ups")

?: vous donne un moyen de gérer élégamment le cas de repli même si vous avez plusieurs niveaux de repli. Si tel est le cas, vous pouvez simplement chaîner plusieurs opérateurs Elvis, comme ici :

val l = listOf(1, 2, 3)

val x = l.firstOrNull { it == 4 } ?: l.firstOrNull { it == 5 } ?: throw IllegalStateException("Ups")

Si vous deviez exprimer la même chose avec un if else, cela nécessiterait beaucoup plus de code qui serait plus difficile à lire.

5voto

Romman Points 21

En fait, vous avez deux mains. Si votre main gauche ne fonctionne pas, return empty sinon busy

Exemple pour Java :

private int a;
if(a != null){
    println("a n'est pas nul, sa valeur est: "+a)
}
else{
    println("a est nul")
}

Exemple pour Kotlin :

val a : Int = 5
val l : Int = if (a != null) a.length else "a est nul"

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X