How do I run a block of code if a nullable type is null?
KotlinKotlin Null-SafetyKotlin Problem Overview
In Kotlin, I can run code if an object is not null like this:
data?.let {
// execute this block if not null
}
But how can I execute a block of code if the object is null?
Kotlin Solutions
Solution 1 - Kotlin
You can use the elvis operator and evaluate another block of code with run { ... }
:
data?.let {
// execute this block if not null
} ?: run {
// execute this block if null
}
But this seems not to be quite as readable as a simple if
-else
statement.
Also, you might find this Q&A useful:
Solution 2 - Kotlin
Here's a concise syntax using the Elvis operator. Recall the Elvis operator only executes the right side if the left side evaluates to null.
data ?: doSomething()
Solution 3 - Kotlin
You can create an infix function like this:
infix fun Any?.ifNull(block: () -> Unit) {
if (this == null) block()
}
Then you can do this:
data ifNull {
// Do something
}
Solution 4 - Kotlin
Just use a normal if
:
if (data == null) {
// Do something
}
Solution 5 - Kotlin
You can use below code
myNullable?.let {
} ?: {
// do something
}()
also you can omit fun()
myNullable?.let {
} ?: fun() {
// do something
}()
or you can call invoke()
instead of ()
myNullable?.let {
} ?: fun() {
// do something
}.invoke()
Note that returning value differs like below.
val res0 = myNullable?.let {
} ?: () {
}()
val res1 = myNullable?.let {
} ?: fun() {
"result"
}()
val res2 = myNullable?.let {
} ?: () {
"result"
}()
println("res0:$res0")
println("res1:$res1")
println("res2:$res2")
RESULT:
res0:kotlin.Unit // () {} with empty
res1:kotlin.Unit // fun() {}
res2:result // () {} with return
Solution 6 - Kotlin
let can apply on null as well, regardless if the object is null or not:
data.let {d->
if (d != null){
// execute this block if data is not null
} else {
// for data is null
}
}
Solution 7 - Kotlin
I prefer this solution,
fun runIfNull(any: Any?, block: () -> Unit) {
if (any == null) block()
}
Which you use as:
runIfNull(any) { // it will run; }
It has an advantage comparing to @Dmitry Ryadnenko's answer,
where one might be confused and might use it incorrectly.
There you have a function
infix fun Any?.ifNull(block: () -> Unit) {
if (this == null) block()
}
And in case you use it on a null object in the way:
nullObject?.ifNull { // THIS WILL NOT BE CALLED }
nullObject.ifNull { // this will be called }
The block is not going to be executed.
Please note the mistakenly added question mark '?'
Solution 8 - Kotlin
Following answer is simpler version of this answer.
Function returns valid list if chain calls are successful
else
returns emptyList()
class A(var b: B? = null)
class B(var c: C? = null)
class C(var d: D? = null)
class D(var list: List<String>?)
//1. Note ? in A?.<functionName>
fun A?.isNull(): List<String> {
if(this == null) { // 2. access object using this keyword
return emptyList<String>()
}
return this.b?.c?.d?.list ?: emptyList<String>()
}
fun main() {
//1. Empty A object
var a: A? = A()
println(a.isNull()) //[]
//2. Null A object
a = null
println(a.isNull()) //[]
//3. All Valid chaining parameters
val d = D(listOf("d"))
val c = C(d)
var b : B? = B(c)
a = A(b)
println(a.isNull()) //[d]
//4. Invalid chain parameter
b = null
a = A(b)
println(a.isNull()) //[]
}