75

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?

Adil Hussain
  • 30,049
  • 21
  • 112
  • 147
Toni Joe
  • 7,715
  • 12
  • 50
  • 69

8 Answers8

182

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:

hotkey
  • 140,743
  • 39
  • 371
  • 326
52

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()
M. Palsich
  • 1,748
  • 13
  • 18
30

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
}
Dmitry Ryadnenko
  • 22,222
  • 4
  • 42
  • 56
24

Just use a normal if:

if (data == null) {
  // Do something
}
Pixel Elephant
  • 20,649
  • 9
  • 66
  • 83
  • 1
    And what if data is mutable in a concurrent environment? – Alwyn Schoeman Aug 17 '21 at 17:42
  • @AlwynSchoeman Your current function is continuing synchronously and doing whatever you wanted to do in the case `data` was null at the moment you checked it. If you need to prevent it from being set to some other value while this if block is running, you must `synchronize` on something whenever working with the property. – Tenfour04 Nov 09 '21 at 15:16
  • @Tenfour04 threads... – Jeffrey Blattman Jul 19 '22 at 19:22
15

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
iroiroys
  • 788
  • 1
  • 10
  • 17
  • `let` will apply the function with `myNullable` as object even if `myNullable` is null. – ssasi May 19 '22 at 10:58
  • @ssasi Could you describe more specific your case? I wrote the answer two years ago, this is needed to be updated if there're something error. – iroiroys May 19 '22 at 23:25
2

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
    }
}

lannyf
  • 9,865
  • 12
  • 70
  • 152
0

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 '?'

Leo DroidCoder
  • 14,527
  • 4
  • 62
  • 54
0

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()) //[]
}
dkb
  • 4,389
  • 4
  • 36
  • 54