skip to content

What do takeIf and takeUnless do, and what does each return?

level: juniorimportance: must knowfreq 55%

answer

  1. takeIf = keep value if true, else null
  2. takeUnless = keep value if false, else null
  3. Return type is always T? (nullable)
  4. Pairs with Elvis ?: for defaults
  5. inline extension on generic T

basics

~10 s

takeIf 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 s

Both 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 lines
kotlin
val 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

for a junior

Knows takeIf returns value-or-null and takeUnless is its inverse, and can use it with ?:.

for a middle

Knows the result is nullable T?, that they are inline extension functions, and the takeUnless = takeIf{!p} equivalence.

for a senior

Explains the inline/no-allocation benefit and picks the form that reads best, avoiding double negatives.

for a principal

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

context