I can't figure out what ?:
does in for example this case
val list = mutableList ?: mutableListOf()
and why can it be modified to this
val list = if (mutableList != null) mutableList else mutableListOf()
I can't figure out what ?:
does in for example this case
val list = mutableList ?: mutableListOf()
and why can it be modified to this
val list = if (mutableList != null) mutableList else mutableListOf()
The Elvis operator is part of many programming languages, e.g. Kotlin but also Groovy or C#. I find the Wikipedia definition pretty accurate:
In certain computer programming languages, the Elvis operator
?:
is a binary operator that returns its first operand if that operand istrue
, and otherwise evaluates and returns its second operand. It is a variant of the ternary conditional operator,? :
, found in those languages (and many others): the Elvis operator is the ternary operator with its second operand omitted.
The following is especially true for Kotlin:
Some computer programming languages have different semantics for this operator. Instead of the first operand having to result in a boolean, it must result in an object reference. If the resulting object reference is not
null
, it is returned. Otherwise the value of the second operand (which may benull
) is returned.
An example: x ?: y
// yields x
if x
is not null, y
otherwise.
This is called the Elvis operator and it does... Exactly what you've described in your question. If its left hand side is a null
value, it returns the right side instead, sort of as a fallback. Otherwise it just returns the value on the left hand side.
a ?: b
is just shorthand for if (a != null) a else b
.
Some more examples with types:
val x: String? = "foo"
val y: String = x ?: "bar" // "foo", because x was non-null
val a: String? = null
val b: String = a ?: "bar" // "bar", because a was null
The Elvis Operator is represented by a question mark followed by a colon: ?:
and it can be used with this syntax:
first operand ?: second operand
It enables you to write a consise code, and works as such:
If first operand
isn't null, then it will be returned. If it is null, then the second operand
will be returned. This can be used to guarantee that an expression won't return a null value, as you'll provide a non-nullable value if the provided value is null.
For example(in Kotlin):
fun retrieveString(): String { //Notice that this type isn't nullable
var nullableVariable: String? = getPotentialNull() //This variable may be null
return nullableVariable ?: "Secondary Not-Null String"
}
In this case, if the computed value of getPotentialNull
is not null, it will be returned by retrieveString
; If it is null, the second expression "Secondary Not-Null String"
will be returned instead.
Also note that the right-hand side expression is evaluated only if the left-hand side is null.
In Kotlin, you could use any expression as second operand
, such as a throw Exception
expression
return nullVariable ?: throw IllegalResponseException("My inner function returned null! Oh no!")
The name Elvis Operator comes from the famous American singer Elvis Presley. His hairstyle resembles a Question Mark
Let's take a look at the defintion:
When we have a nullable reference r, we can say "if r is not null, use it, otherwise use some non-null value x":
The ?:
(Elvis) operator avoids verbosity and makes your code really concise.
For example, a lot of collection extension functions return null
as fallback.
listOf(1, 2, 3).firstOrNull { it == 4 } ?: throw IllegalStateException("Ups")
?:
gives you a way to handle the fallback case elgantely even if you have multiple layers of fallback. If so, you can simply chain multiply Elvis operators, like here:
val l = listOf(1, 2, 3)
val x = l.firstOrNull { it == 4 } ?: l.firstOrNull { it == 5 } ?: throw IllegalStateException("Ups")
If you would express the same with if else it would be a lot more code which is harder to read.