What do takeIf and takeUnless do, and what does each return?
answer
- takeIf = keep value if true, else null
- takeUnless = keep value if false, else null
- Return type is always T? (nullable)
- Pairs with Elvis ?: for defaults
- inline extension on generic T
basics
~10 stakeIf returns the value if a condition is true, otherwise null. takeUnless is the opposite: it returns the value if the condition is false, otherwise null.
solid answer
~40 sBoth are inline extension functions on a generic receiver T defined in the Kotlin standard library. `takeIf { predicate }` evaluates the lambda with the receiver as `it`; if the predicate returns true it returns the receiver, otherwise `null`. `takeUnless { predicate }` is the exact inverse: it returns the receiver when the predicate is false, otherwise `null`. Because both can return `null`, their result type is `T?` (nullable). They are most commonly chained with the Elvis operator `?:` to supply a fallback, e.g. `name.takeIf { it.isNotBlank() } ?: "anonymous"`. They turn an imperative if/else that produces a value into a single fluent expression.
code
kotlin · 5 linesval name = " "
val cleaned: String? = name.takeIf { it.isNotBlank() } // null
val display = name.takeIf { it.isNotBlank() } ?: "anonymous" // "anonymous"
val even = 7.takeUnless { it % 2 == 0 } // 7 (odd, so kept)go deeper
Knows takeIf returns value-or-null and takeUnless is its inverse, and can use it with ?:.
Knows the result is nullable T?, that they are inline extension functions, and the takeUnless = takeIf{!p} equivalence.
Explains the inline/no-allocation benefit and picks the form that reads best, avoiding double negatives.
Frames them as expression-oriented replacements for value-producing if/else and sets team conventions for when fluency aids vs. hurts readability.
## What they are `takeIf` and `takeUnless` are two small but expressive functions in the Kotlin standard library (`kotlin.standard`). They are **inline extension functions** declared on a generic receiver `T`, meaning you can call them on *any* value. Their signatures are essentially: ```kotlin public inline fun <T> T.takeIf(predicate: (T) -> Boolean): T? public inline fun <T> T.takeUnless(predicate: (T) -> Boolean): T? ``` ## Behaviour - `takeIf { ... }`: runs the predicate lambda; the receiver is available inside as `it`. If the predicate returns **true**, the function returns the **receiver** (the original value). If it returns **false**, it returns **null**. - `takeUnless { ... }`: the inverse. Returns the receiver if the predicate is **false**, otherwise **null**. Because either can return `null`, the **return type is `T?`** (nullable), even when the receiver itself is non-null. ## Why they exist They turn a value-producing if/else into a fluent, chainable expression. Instead of: ```kotlin val result = if (input.isNotBlank()) input else null ``` you write: ```kotlin val result = input.takeIf { it.isNotBlank() } ``` They shine when combined with the **Elvis operator `?:`** to provide a default or trigger an early action: ```kotlin val port = configValue.takeIf { it in 1..65535 } ?: 8080 val token = header.takeUnless { it.isBlank() } ?: error("missing token") ``` ## inline Because both are marked `inline`, the lambda is compiled into the call site — there is no function-object allocation and no real call overhead. This makes them essentially free to use. ## takeIf vs takeUnless They are logically equivalent: `x.takeUnless { p }` equals `x.takeIf { !p }`. Choose whichever reads more naturally; `takeUnless` avoids a negation in the predicate.
- What is the return type of someString.takeIf { it.isNotEmpty() }?String? — nullable, because takeIf returns null when the predicate is false.
A bouncer: takeIf lets the value through only if it meets the condition, otherwise it leaves with nothing (null).
saying these in an interview costs you the question
- Saying takeIf returns a Boolean
- Saying the result is non-nullable
- Confusing the directions of takeIf and takeUnless
- Thinking they mutate the receiver