Opérateur conditionnel ternaire Kotlin

Réponses:

619

Dans Kotlin, les ifdéclarations sont des expressions. Le code suivant est donc équivalent:

if (a) b else c

La distinction entre expression et déclaration est ici importante. En Java / C # / JavaScript, ifforme une instruction, ce qui signifie qu'elle ne se résout pas en une valeur. Plus concrètement, vous ne pouvez pas l'affecter à une variable.

// Valid Kotlin, but invalid Java/C#/JavaScript
var v = if (a) b else c

Si vous venez d'une langue où ifest une déclaration, cela peut sembler contre nature, mais ce sentiment devrait bientôt disparaître.

Drew Noakes
la source
57
De plus, vous pouvez utiliser when.
bashor
5
juste pour ajouter, si c'est une expression booléenne, vous pouvez même aller avecx = a==b
gnomeria
2
@MikeRylander J'ai étendu la réponse pour rendre cela explicite. Merci de l'avoir signalé.
Drew Noakes
1
@AdeelAnsari Non, ce n'est pas en train de rectifier. C'est pire. Comparez cela. b + if (a) c else dcontre b + (c if (a) else d)ce dernier nécessite des parenthèses supplémentaires. car cn'est pas entouré par la condition et else.
Naetmul
1
Voici une petite discussion sur ce sujet. discussion.kotlinlang.org/t/ternary-operator/2116/141
F. Norbert
70

Vous pouvez définir votre propre Booleanfonction d'extension qui retourne nulllorsque le Booleanest falsede fournir une structure similaire à l'opérateur ternaire:

infix fun <T> Boolean.then(param: T): T? = if (this) param else null

Cela ferait a ? b : ctraduire une expression a then b ?: ccomme suit:

println(condition then "yes" ?: "no")

Mise à jour: Mais pour faire un changement conditionnel de type Java, vous aurez besoin de quelque chose comme ça

infix fun <T> Boolean.then(param: () -> T): T? = if (this) param() else null

println(condition then { "yes" } ?: "no") faites attention à la lambda. le calcul du contenu devrait être reportée jusqu'à ce que nous nous assurons conditionesttrue

Celui-ci a l'air maladroit, c'est pourquoi il existe une demande très élevée pour porter l'opérateur ternaire Java dans Kotlin

déviant
la source
1
infix inline fun<T> Boolean.then(param: ()->T):T? = if(this) param() else null
nullbyte
3
Utilisez <T: Any>, sinon cela ne fonctionnera pas correctement:true then { null } ?: "not-null"
Eugene Petrenko
BTW, l' ?:opérateur ici est elvis-operator: kotlinlang.org/docs/reference/null-safety.html#elvis-operator
Eric Wang
64

TL; DR

if (a) b else c

est ce que vous pouvez utiliser à la place de l'expression d'opérateur ternaire a ? b : c.


Dans Kotlin, de nombreuses déclarations de contrôle , y compris if, whenou même trypeut être utilisé comme expressions . Cela signifie que ceux-ci peuvent avoir un résultat qui peut être affecté à une variable, renvoyé par une fonction, etc.

Syntaxiquement, aucun opérateur ternaire n'est nécessaire

Du fait des expressions de Kotlin, le langage n'a pas vraiment besoin de l'opérateur ternaire .

if (a) b else c

est ce que vous pouvez utiliser à la place de l'expression d'opérateur ternaire a ? b : c.

Je pense que l'idée est que l'ancienne expression est plus lisible car tout le monde sait ce que ifelsefait, alors qu'elle ? :n'est pas claire si vous n'êtes pas déjà familier avec la syntaxe.

Néanmoins, je dois admettre que je manque souvent l'opérateur ternaire le plus pratique.


Autres alternatives

quand

Vous pouvez également voir des whenconstructions utilisées dans Kotlin lorsque les conditions sont vérifiées. C'est aussi un moyen d'exprimer les cascades if-else d'une manière alternative. Ce qui suit correspond à l'exemple des OT.

when(a) {
    true -> b
    false -> c
}

Extensions

Comme le montrent de nombreux bons exemples ( opérateur conditionnel ternaire de Kotlin ) dans les autres réponses, les extensions peuvent également vous aider à résoudre votre cas d'utilisation.

s1m0nw1
la source
36

Pour moi, j'utilise les fonctions d'extension suivantes:

fun T?.or<T>(default: T): T = if (this == null) default else this 
fun T?.or<T>(compute: () -> T): T = if (this == null) compute() else this

Le premier retournera la valeur par défaut fournie dans le cas où l'objet est égal à null. Le second évaluera l'expression fournie dans lambda dans le même cas.

Usage:

1) e?.getMessage().or("unknown")
2) obj?.lastMessage?.timestamp.or { Date() }

Personnellement, le code ci-dessus est plus lisible que la ifconstruction en ligne

ruX
la source
34
Ce n'est pas pertinent pour la question, mais pourquoi ne pas utiliser ?: , L' opérateur elvis ? La première fonction serait remplacée par e.getMessage() ?: "unknown". Le second peut être exprimé comme obj?.lastMessage?.timestamp ?: { Date() }()
raccourci clavier le
1
@hotkey il n'y a pas de but particulier pour cela. De mon point de vue, il semble plus cohérent et visuellement moins bruyant dans les opérations de chaîne, car vous ne devriez pas envelopper la construction dans les supports
ruX
14
@ruX l'opérateur elvis est spécialement conçu pour cela et votre utilisation est plutôt inhabituelle.
Jayson Minard
6
Alors?: Ça va, n'allons pas trop loin sur la route de Perl.
Richard Haven
28

Il n'y a pas d'opérateur ternaire dans kotlin, car le if elsebloc renvoie une valeur

vous pouvez donc faire: val max = if (a > b) a else b au lieu de javamax = (a > b) ? b : c

On peut aussi utiliser la whenconstruction, ça renvoie aussi de la valeur:

val max = when(a > b) {
    true -> a
    false -> b
}

Voici le lien pour la documentation de kotlin: Flux de contrôle: if, when, for, while

romiope
la source
27

Dans Kotlin, ifest une expression, c'est-à-dire qu'elle renvoie une valeur. Il n'y a donc pas d'opérateur ternaire (condition ? then : else), car ordinaire si fonctionne bien dans ce rôle. source manuelle d'ici

// Traditional usage 
var max = a 
if (a < b) max = b

// With else 
var max: Int
if (a > b) {
    max = a
} else {
    max = b
}

// As expression 
val max = if (a > b) a else b
Kris Roofe
la source
26

Quelques cas d'angle non mentionnés dans d'autres réponses.

Depuis l'apparition de takeIf dans Kotlin 1.1, l'opérateur ternaire a ? b : cpeut également être exprimé comme ceci:

b.takeIf { a } ?: c

Cela devient encore plus court dans le cas où c est null:

b.takeIf { a }

Notez également que dans le monde Java, les vérifications nulles comme value != null ? value : defaultValuetraduire dans Kotlin idéomatique en juste value ?: defaultValue.

Similaire a != null ? b : cpeut être traduit en a?.let { b } ?: c.

Vadzim
la source
6
Comment est b.takeIf { a } ?: cplus court et plus lisible que if (a) b else c? L'opérateur de Terneray est certainement une fonctionnalité manquante dans Kotlin car les noms de variables et la condition peuvent être longs et vous obliger à diviser la ligne, ce qui est mauvais
Javad Sadeqzadeh
1
Il convient également de noter que takeIftoujours évalue le cas réel (ici a). Non seulement cette expression peut être calculée inutilement s'il ase trouve qu'elle est fausse, mais vous ne pouvez pas bénéficier de modèles intelligents à la if (a is Int) { a + 3 }.
TheOperator
@TheOperator, faux. { a }est un lambda évalué paresseusement.
Vadzim
1
Je l'ai mal écrit, devrait être "évalue toujours le vrai cas (ici b)". Mais même { a }, bien que paresseux, doit être évalué pour déterminer le résultat de l'expression.
TheOperator
24

Jetez un œil aux documents :

Dans Kotlin, if est une expression, c'est-à-dire qu'il renvoie une valeur. Il n'y a donc pas d'opérateur ternaire (condition? Alors: else), car ordinaire si fonctionne bien dans ce rôle.

Li Ying
la source
13

Java

int temp = a ? b : c;

Équivalent à Kotlin:

var temp = if (a) b else c
doubleThunder
la source
12

TÂCHE :

Prenons l'exemple suivant:

if (!answer.isSuccessful()) {
    result = "wrong"
} else {
    result = answer.body().string()
}
return result

Nous avons besoin de l'équivalent suivant dans Kotlin:

return (! answer.isSuccessful ()) ? "incorrect" : answer.body (). string ()


SOLUTIONS :

1.A . Vous pouvez utiliser if-expressiondans Kotlin:

return if (!answer.isSuccessful()) "wrong" else answer.body().string()

1.b . Cela peut être bien mieux si vous retournez ceci if-expression(faisons-le sans not):

return if (answer.isSuccessful()) answer.body().string() else "wrong"

2 . L'opérateur Elvis de Kotlin ?:peut faire un travail encore mieux:

return answer.body()?.string() ?: "wrong"

3 . Ou utilisez un Extension functionpour la Answerclasse correspondante :

fun Answer.bodyOrNull(): Body? = if (isSuccessful()) body() else null

4 . En utilisant le, Extension functionvous pouvez réduire un code grâce à Elvis operator:

return answer.bodyOrNull()?.string() ?: "wrong"

5 . Ou utilisez simplement l' whenopérateur:

when (!answer.isSuccessful()) {
    parseInt(str) -> result = "wrong"
    else -> result = answer.body().string()
}

J'espère que cela t'aides.

Andy
la source
11

quand remplace l'opérateur de commutation des langages de type C. Dans sa forme la plus simple, cela ressemble à ceci

when (x) {
    1 -> print("x == 1")
    2 -> print("x == 2")
    else -> {
        print("x is neither 1 nor 2")
    }
}
Guruprasath
la source
3
Vrai, mais l'exemple que vous montrez a whenune déclaration, pas une expression. Une comparaison plus pertinente avec les expressions conditionnelles ternaires consisterait à ce que chaque branche renvoie une valeur, de sorte que l'expression when entière soit évaluée à une valeur (comme cela se produit avec les conditions ternaires).
Drew Noakes
9

Il n'y a pas d'opérateur ternaire à Kotlin. Cela semble problématique à première vue. Mais pensez que nous pouvons le faire avec l'instruction inline if else car c'est l'expression ici. Nous devons simplement faire -

var number = if(n>0) "Positive" else "Negetive"

Ici, nous pouvons le faire si nous en bloquons trop. Comme-

var number = if(n>0) "Positive" else if(n<0) "Negative" else "Zero"

Cette ligne est donc tellement simple et beaucoup plus lisible que l'opérateur ternaire. lorsque nous utilisons plus d'un opérateur ternaire en java, cela semble horrible. Mais ici, nous avons une syntaxe claire. même nous pouvons également l'écrire sur plusieurs lignes.

HM Nayem
la source
9

Vous pouvez utiliser var a= if (a) b else cà la place de l'opérateur ternaire.

Un autre bon concept de kotlin est l'opératrice Elvis. Vous n'avez pas besoin de vérifier null à chaque fois.

val l = b?.length ?: -1

Cela retournera la longueur si b n'est pas nul sinon il exécute l'instruction du côté droit.

Android Geek
la source
7

comme l'a dit Drew Noakes, kotlin utilise l'instruction if comme expression, donc l'opérateur conditionnel ternaire n'est plus nécessaire,

mais avec la fonction d'extension et la surcharge des infixes, vous pouvez l'implémenter vous-même, voici un exemple

infix fun <T> Boolean.then(value: T?) = TernaryExpression(this, value)

class TernaryExpression<out T>(val flag: Boolean, val truly: T?) {
    infix fun <T> or(falsy: T?) = if (flag) truly else falsy
}

puis utilisez-le comme ça

val grade = 90
val clazz = (grade > 80) then "A" or "B"
Minami
la source
Peut-être supprimer <T> mieux fun infixer fun ou (falsy: T?) = If (flag) vraiment autre chose falsy
solo
1
Mais ajouter <T> peut le faire fonctionner: (grade> 80) puis null ou "B"
solo
C'est vraiment cool, je vais l'utiliser: P Mais notez que, sauf erreur, cela provoquera une allocation d'objet à chaque appel. Ce n'est pas énorme, mais il faut savoir que ce n'est pas une abstraction à coût nul.
Adam
6

Une autre approche intéressante serait d'utiliser when:

when(a) {
  true -> b
  false -> b
}

Peut être très pratique dans certains scénarios plus complexes. Et honnêtement, c'est plus lisible pour moi queif ... else ...

Grzegorz Piwowarek
la source
6

Vous pouvez le faire de nombreuses façons à Kotlin

  1. Utilisation de if

    if(a) b else c
  2. Utiliser quand

    when (a) { 
        true -> print("value b") 
        false -> print("value c") 
        else -> {  
            print("default return in any other case") 
        } 
    }
  3. Sécurité nulle

    val a = b ?: c
Rajesh Dalsaniya
la source
5

Il n'y a pas d'opération ternaire à Kotlin, mais il existe des façons amusantes de contourner cela. Comme d'autres l'ont souligné, une traduction directe dans Kotlin ressemblerait à ceci:

val x = if (condition) result1 else result2

Mais, personnellement, je pense que cela peut devenir un peu encombré et difficile à lire. Il existe d'autres options intégrées à la bibliothèque. Vous pouvez utiliser takeIf {} avec un opérateur elvis:

val x = result1.takeIf { condition } ?: result2

Ce qui se passe là-bas, c'est que la commande takeIf {} retourne votre résultat1 ou null, et l'opérateur elvis gère l'option null. Il y a quelques options supplémentaires, takeUnless {}, par exemple:

val x = result1.takeUnless { condition } ?: result2

Le langage est clair, vous savez ce que ça fait.

Si c'est une condition couramment utilisée, vous pouvez également faire quelque chose d'amusant comme utiliser une méthode d'extension en ligne. Supposons que nous voulons suivre un score de jeu comme un Int, par exemple, et nous voulons toujours retourner 0 si une condition donnée n'est pas remplie:

inline fun Int.zeroIfFalse(func: () -> Boolean) : Int = if (!func.invoke()) 0 else this     

Ok, ça semble moche. Mais considérez à quoi il ressemble quand il est utilisé:

var score = 0
val twoPointer = 2
val threePointer = 3

score += twoPointer.zeroIfFalse { scoreCondition } 
score += threePointer.zeroIfFalse { scoreCondition } 

Comme vous pouvez le voir, Kotlin offre une grande flexibilité dans la façon dont vous choisissez d'exprimer votre code. Il existe d'innombrables variantes de mes exemples et probablement des façons que je n'ai même pas encore découvert. J'espère que ça aide!

pranalli
la source
takeIfest mon option préférée en effet, très élégante.
Javier Mendonça
4

Rappelez-vous que l' opérateur ternaire et l' opérateur Elvis ont des significations distinctes dans Kotlin contrairement à de nombreuses langues populaires. Faire expression? value1: value2vous donnerait de mauvais mots par le compilateur Kotlin , contrairement à toute autre langue car il n'y a pas d'opérateur ternaire dans Kotlin comme mentionné dans les documents officiels . La raison en est que les instructions if, when et try-catch renvoient elles - mêmes des valeurs.

Donc, faire expression? value1: value2peut être remplacé par

val max = if (a> b) print ("Choose a") else print ("Choose b")

L' opérateur Elvis que Kotlin a, ne fonctionne que dans le cas des variables annulable ex .:

Si je fais quelque chose comme ça value3 = value1 ?: value2alors si value1 est null alors value2 serait retourné sinon value1 serait retourné.

Une compréhension plus claire peut être obtenue à partir de ces réponses .

Neeraj Sewani
la source
3

Vous pouvez utiliser l' ifexpression pour cela dans Kotlin. Dans Kotlin ifest une expression avec une valeur de résultat. Donc, à Kotlin, nous pouvons écrire

fun max(a: Int, b: Int) = if (a > b) a else b

et en Java, nous pouvons réaliser la même chose mais avec un code plus grand

int max(int a, int b) {
return a > b ? a : b
}
Gulzar Bhat
la source
2

Si vous ne savez pas quoi utiliser la notation standard, vous pouvez également la créer / simuler en utilisant infix avec quelque chose comme ceci:

créer une classe pour contenir votre cible et résultat:

data class Ternary<T>(val target: T, val result: Boolean)

créer des fonctions d'infixe pour simuler une opération ternaire

infix fun <T> Boolean.then(target: T): Ternary<T> {
    return Ternary(target, this)
}

infix fun <T> Ternary<T>.or(target: T): T {
    return if (this.result) this.target else target
}

Ensuite, vous pourrez l'utiliser comme ceci:

val collection: List<Int> = mutableListOf(1, 2, 3, 4)

var exampleOne = collection.isEmpty() then "yes" or "no"
var exampleTwo = (collection.isNotEmpty() && collection.contains(2)) then "yes" or "no"
var exampleThree = collection.contains(1) then "yes" or "no"
Eudy Contreras
la source
Pour l'avoir complètement équivalent à un opérateur ternaire réel, les valeurs cibles peuvent également être lambda fournissant T
Old Man of Aran
1

Une autre approche courte à utiliser

val value : String = "Kotlin"

value ?: ""

Ici, kotlin vérifie lui-même la valeur nulle et s'il est nul, il transmet une valeur de chaîne vide.

Vinod Pattanshetti
la source
1

Pourquoi utiliserait-on quelque chose comme ça:

when(a) {
  true -> b
  false -> b
}

quand vous pouvez réellement utiliser quelque chose comme ça ( aest booléen dans ce cas):

when {
  a -> b
  else -> b
}
ZZ 5
la source
1
Parce que le premier est sémantiquement clair et facilement compréhensible pour quelqu'un d'autre qui le lit même s'il n'est pas familier avec Kotlin, tandis que le second ne l'est pas.
mc01
1
Eh bien, vous avez compris, mais je ne comprends pas pourquoi les développeurs de Kotlin n'ont pas introduit l'expression ternaire
ZZ 5
Je pense que cela ? and :contredit la déclaration nullable / type plutôt qu'une vérification de type. En dehors de cela, je ne vois aucune raison. Je pense que quelqu'un aurait certainement réfléchi, s'il y avait un contrôle conditionnel if-else en ligne. Attendons de voir dans les futures versions.
bh4r4th
1

Lorsque vous travaillez avec apply (), laissez semble très pratique lorsqu'il s'agit d'opérations ternaires, car il est plus élégant et vous donne de la place

val columns: List<String> = ...
val band = Band().apply {
    name = columns[0]
    album = columns[1]
    year = columns[2].takeIf { it.isNotEmpty() }?.let { it.toInt() } ?: 0
}
Juan Mendez
la source
0

Avec les fonctions d'infixe suivantes, je peux couvrir de nombreux cas d'utilisation courants à peu près de la même manière que cela peut être fait en Python:

class TestKotlinTernaryConditionalOperator {

    @Test
    fun testAndOrInfixFunctions() {
        Assertions.assertThat(true and "yes" or "no").isEqualTo("yes")
        Assertions.assertThat(false and "yes" or "no").isEqualTo("no")

        Assertions.assertThat("A" and "yes" or "no").isEqualTo("yes")
        Assertions.assertThat("" and "yes" or "no").isEqualTo("no")

        Assertions.assertThat(1 and "yes" or "no").isEqualTo("yes")
        Assertions.assertThat(0 and "yes" or "no").isEqualTo("no")

        Assertions.assertThat(Date() and "yes" or "no").isEqualTo("yes")
        @Suppress("CAST_NEVER_SUCCEEDS")
        Assertions.assertThat(null as Date? and "yes" or "no").isEqualTo("no")
    }
}

infix fun <E> Boolean?.and(other: E?): E? = if (this == true) other else null
infix fun <E> CharSequence?.and(other: E?): E? = if (!(this ?: "").isEmpty()) other else null
infix fun <E> Number?.and(other: E?): E? = if (this?.toInt() ?: 0 != 0) other else null
infix fun <E> Any?.and(other: E?): E? = if (this != null) other else null
infix fun <E> E?.or(other: E?): E? = this ?: other
Nicolas Cornette
la source
0

Il n'y a pas d'opérateur ternaire à Kotlin, les plus fermés sont les deux cas ci-dessous,

  • If else as expression statement

val a = true if(a) print("A is true") else print("A is false")

  • Opérateur Elvis

Si l'expression à gauche de?: N'est pas nulle, l'opérateur elvis la renvoie, sinon elle renvoie l'expression à droite. Notez que l'expression de droite n'est évaluée que si la gauche est nulle.

 val name = node.getName() ?: throw IllegalArgumentException("name expected")

Documents de référence

JTeam
la source
0

exemple: var energy: Int = data? .get (position) ?. energy? .toInt ()?: 0

Dans kotlin si vous utilisez ?: Cela fonctionnera comme si l'instruction retournera null alors ?: 0 cela prendra 0 ou tout ce que vous avez écrit de ce côté.

abhilasha Yadav
la source
-1

Dans Kotlin, vous pouvez utiliser une opération ternaire comme celle-ci: val x = if(a) "add b" else "add c"

manuelernest0
la source
1
Cette question a déjà reçu une réponse suffisante et n'a pas été mise à jour récemment. Il n'est pas nécessaire de poster maintenant une autre réponse qui ne diffère pas des précédentes.
Headcracker
-2

Après quelques recherches sur d'autres idées, j'ai dérivé l'opérateur ternaire suivant:

infix fun <T : Any> Boolean.yes(trueValue: T): T? = if (this) trueValue else null
infix fun <T : Any> T?.no(falseValue: T): T = this ?: falseValue

Exemple (exécutez ici ):

fun main() {
    run {
        val cond = true
        val result = cond yes "True!" no "False!"
        println("ternary test($cond): $result")
    }
    run {
        val cond = false
        val result = cond yes "True!" no "False!"
        println("ternary test($cond): $result")
    }
}

Cette version est courante et n'entre pas en conflit avec l'opérateur de coalescence nul.

Bryan W. Wagner
la source
C'est un peu la même chose que la réponse de deviant où elle est nommée thenau lieu de yes.
Ry-
@Ry oui, et je ne sais pas s'ils sont la même personne mais l'idée d'utiliser des méthodes d'infixe avec des options vient du forum Kotlin. Ce que je n'ai pas vu, c'est la méthode `` non '' que j'ai trouvée car je trouve l'utilisation en ligne de l'opérateur de coalescence nulle déroutante parce que le point d'interrogation se trouve après la `` valeur alors '' au lieu de la condition comme c'est le cas dans la plupart des langues.
Bryan W. Wagner