In Kotlin, takeIf and takeUnless are scope-style functions used to keep or discard a value based on a condition.
takeIf
takeIf returns the object itself if the predicate is true; otherwise it returns null.
val result = value.takeIf { condition }
Equivalent to:
val result = if (condition) value else null
Example
val number = 10
val evenNumber = number.takeIf { it % 2 == 0 }
println(evenNumber) // 10
If the condition fails:
val number = 7
val evenNumber = number.takeIf { it % 2 == 0 }
println(evenNumber) // null
takeUnless
takeUnless is the opposite of takeIf.
It returns the object itself if the predicate is false; otherwise it returns null.
val result = value.takeUnless { condition }
Equivalent to:
val result = if (!condition) value else null
Example
val number = 7
val notEvenNumber = number.takeUnless { it % 2 == 0 }
println(notEvenNumber) // 7
If the condition is true:
val number = 10
val notEvenNumber = number.takeUnless { it % 2 == 0 }
println(notEvenNumber) // null
Common use with safe calls
Because both functions can return null, they are often used with ?.let.
val input = "kotlin"
input
.takeIf { it.length > 3 }
?.let {
println("Valid input: $it")
}
This prints:
Valid input: kotlin
If the condition fails, let is skipped:
val input = "hi"
input
.takeIf { it.length > 3 }
?.let {
println("Valid input: $it")
}
Nothing is printed.
Practical examples
Validate a string
fun normalizeUsername(username: String): String? {
return username
.trim()
.takeIf { it.length >= 3 }
?.lowercase()
}
Usage:
println(normalizeUsername(" Alice ")) // alice
println(normalizeUsername(" a ")) // null
Reject blank input
val name = userInput.takeUnless { it.isBlank() }
This keeps userInput only if it is not blank.
Equivalent to:
val name = if (!userInput.isBlank()) userInput else null
Parse only valid values
val age = input
.toIntOrNull()
?.takeIf { it >= 0 }
This gives you a non-negative integer or null.
println("42".toIntOrNull()?.takeIf { it >= 0 }) // 42
println("-5".toIntOrNull()?.takeIf { it >= 0 }) // null
println("abc".toIntOrNull()?.takeIf { it >= 0 }) // null
Important note
The predicate runs on the object itself, available as it.
val text = "Kotlin"
val result = text.takeIf { it.startsWith("K") }
Here, it is "Kotlin".
When to use which
Use takeIf when you want to keep a value if a condition is true:
val activeUser = user.takeIf { it.isActive }
Use takeUnless when you want to keep a value unless a condition is true:
val visibleUser = user.takeUnless { it.isDeleted }
In short:
value.takeIf { predicate } // value if predicate is true, else null
value.takeUnless { predicate } // value if predicate is false, else null
