Using Kotlin takeIf (or takeUnless)

In Kotlin’s standard functions, there’s two function i.e. takeIf and takeUnless, that at first glance, what’s so special about it? Is it pretty much just if?

Or one could go the extreme, replace every if it sees as below (NOT recommended).

// Original Code
if (status) { doThis() }
// Modified Code
takeIf { status }?.apply { doThis() }

Under the hood

Like any other thing, takeIf (or takeUnless) do have it’s place of use. I share my view of them in the various scenario. Before we proceed, let’s look at the implementation of it.

The implementation signature

public inline fun <T> T.takeIf(predicate: (T) -> Boolean): T? 
= if (predicate(this)) this else null

From it, we notice that

  1. It is called from the T object itself. i.e. T.takeIf.
  2. The predicate function takes T object as parameter
  3. It returns this or null pending on the predicate evaluation.

Appropriate use

Based on the characteristics above, I could derive it’s usage as oppose to if condition in the below scenarios.

1. It is called from the T object itself. i.e. T.takeIf.

The benefit of handling cases with nullability check. An example as below

// Original code
if (someObject != null && status) {
doThis()
}
// Improved code
someObject?.takeIf{ status }?.apply{ doThis() }

2. The predicate function takes T object as parameter

Given this takes T as parameter to the predicate, one could further simply the code with takeIf as below

// Original code
if (someObject != null && someObject.status) {
doThis()
}
// Better code
if (someObject?.status == true) {
doThis()
}
// Improved code
someObject?.takeIf{ it.status }?.apply{ doThis() }

The better code helps, but requires additional explicit eyesore true keyword in the evaluation. So it’s not ideal.

3. It returns this or null pending on the predicate evaluation.

Since it is returning this if it is true, it could be used for chaining the operation. Hence something as below would be improved.

// Original code
if (someObject != null && someObject.status) {
someObject.doThis()
}
// Improved code
someObject?.takeIf{ status }?.doThis()

Or a better way of getting some data or quit (example taken from Kotlin Doc)

val index 
= input.indexOf(keyword).takeIf { it >= 0 } ?: error("Error")
val outFile 
= File(outputDir.path).takeIf { it.exists() } ?: return false

Be cautious

One word of cautious though. Check out the below code.

// Syntactically still correct. But logically wrong!!
someObject?.takeIf{ status }.apply{ doThis() }
// The correct one (notice the nullability check ?)
someObject?.takeIf{ status }?.apply{ doThis() }

The first line will just doThis() regardless of if status is true of false. The reason is, even when takeIf returns null, it is still being called. (This is with assumption doThis() is not the function of someObject)

The ? check here is very subtle and most important.


Hopefully the provides some reference how takeIf (or takeUnless) could be better used. Feel free to provide some good real example of how you use these functions as response to this blog. I would love to hear from you. This may benefits others.

Also, for other functions in standard functions, you could refers to my other blog.


I hope you appreciate this post and it’s helpful for you. Do share with others.

You could check out my other interesting topics here.

Follow me on medium, Twitter or Facebook for little tips and learning on Android, Kotlin etc related topics. ~Elye~