skip to content

Null-Handling Operators

The small operator vocabulary you use to work with nullable values: safe call, Elvis fallback, not-null assertion, safe cast, and the let block. Interviewers grade fluency here, because clumsy null handling is immediately visible in code.

part ofKotlinoverview, primer and where to startread it →
on this pageshow

explore

questions

25

What does the Elvis operator ?: do in Kotlin, and what is a typical example of using it?

level: juniorimportance: must knowfreq 80%

answer

  1. left if non-null else right
  2. ?: = null-coalescing
  3. right side short-circuits
  4. pairs with ?.
  5. result is non-null if right is non-null

basics

~10 s

The Elvis operator ?: gives a fallback value when the left side is null. You write a ?: b: if a is not null you get a, otherwise you get b.

solid answer

~40 s

The Elvis operator `a ?: b` evaluates to `a` when `a` is non-null, and to `b` when `a` is null. It is the idiomatic way to supply a default for a nullable expression, replacing verbose `if (a != null) a else b`. The right side is only evaluated when the left is null (short-circuit). The result type is the common supertype of both branches; if the left side is `String?` and the right is a non-null `String`, the overall expression is `String` (smart non-null). It pairs naturally with safe calls, e.g. `name?.trim() ?: "unknown"`. The name comes from the `?:` glyph resembling Elvis Presley's hair and eyes when read sideways.

code

kotlin · 7 lines
kotlin
fun greet(name: String?): String {
    val safeName = name ?: "guest"
    return "Hello, $safeName"
}

println(greet("Ada"))  // Hello, Ada
println(greet(null))   // Hello, guest

go deeper

for a junior

Knows a ?: b returns a when non-null else b, and can write a simple default.

for a middle

Explains short-circuit evaluation and that the result becomes non-null when the right side is non-null.

for a senior

Discusses pairing with ?. chains, side-effect timing on the right, and resulting type inference.

for a principal

Frames Elvis within a broader null-handling policy (defaults vs. fail-fast) and readability/cost trade-offs.

## What the Elvis operator is The **Elvis operator** is written `?:` and has the form `left ?: right`. It is Kotlin's null-coalescing operator: it returns the **left** operand if that operand is **not null**, otherwise it returns the **right** operand. - `null` here means the Kotlin absence-of-value: a variable of a **nullable type** (a type written with a trailing `?`, e.g. `String?`) may hold `null`. - The operator lets you turn a nullable value into a usable default value in one expression. ```kotlin val name: String? = readName() val display: String = name ?: "unknown" // "unknown" when name is null ``` ## Short-circuit evaluation The right side is **only evaluated when the left side is null**. So in `cache ?: computeExpensiveDefault()`, `computeExpensiveDefault()` does not run when `cache` is non-null. This matters when the right side has side effects or is costly. ## Result type The type of `a ?: b` is the **least common supertype** of the two sides. A key consequence: if `a: String?` and `b: String` (non-null), then `a ?: b` has type `String` — non-null — because once you reach this expression either the non-null `a` or the non-null `b` is produced. ## Equivalent without Elvis ```kotlin val display = if (name != null) name else "unknown" ``` The Elvis form is shorter and avoids repeating the expression. ## Common pairing with safe call ?. The **safe call** `?.` returns `null` if its receiver is null. Combined with Elvis you get a default for a whole chain: ```kotlin val len = text?.length ?: 0 ``` Here `text?.length` is `Int?`; Elvis turns it into a plain `Int` defaulting to `0`.

  • Is the right side always evaluated?
    No. It is evaluated only when the left side is null (short-circuit), so side effects on the right run only in the null case.
  • What is the type of `x ?: 0` when `x` is `Int?`?
    `Int` (non-null), because both possible results are non-null.

Like a backup generator: use mains power if it's on, otherwise switch to the generator.

saying these in an interview costs you the question

  • Saying ?: checks for false/zero rather than null
  • Claiming the right side always runs
  • Confusing ?: with the safe call ?.
  • Thinking it works on non-nullable types meaningfully

context

open as a page

What does `value?.let { ... }` do, and what is `it` inside the block?

level: juniorimportance: must knowfreq 80%

basics

~10 s

It runs the block only when value is not null. Inside the block, it is that same value, now guaranteed non-null, so you can use it safely without extra null checks.

open as a page

What does the !! operator do in Kotlin, and what happens at runtime if the value is null?

level: juniorimportance: must knowfreq 80%

basics

~10 s

!! tells the compiler to treat a nullable value as if it is definitely not null. If the value actually is null at runtime, the program crashes with a NullPointerException.

open as a page

What does the safe-call operator ?. do in Kotlin, and what is the type of a?.length when a is a String??

level: juniorimportance: must knowfreq 90%

basics

~20 s

?. only calls the method or reads the property if the value on the left is not null. If it is null, the whole expression is null instead of crashing. So a?.length gives an Int? (a number or null).

open as a page

What is the difference between the `as` and `as?` operators in Kotlin, and what happens at runtime when the value is not of the target type?

level: juniorimportance: must knowfreq 78%

basics

~10 s

as forces a type conversion and crashes with an exception if the value isn't that type. as? tries the same conversion but gives back null instead of crashing when the type doesn't match.

open as a page

How is the Elvis operator used with return and throw for early-exit null guards, and why does it work?

level: middleimportance: must knowfreq 72%

basics

~10 s

You can put return or throw on the right side of ?:. If the left is null, the function returns early or throws; otherwise execution continues with the non-null value.

open as a page

How do you safely access deeply nested nullable properties using `?.`, `?:`, and `?.let`? Show how short-circuiting works across the chain.

level: middleimportance: must knowfreq 70%

basics

~20 s

Chain ?. between each nullable step; if any link is null the whole chain becomes null and stops early. Add ?: at the end for a default, or ?.let { } to run code only when the final value exists.

open as a page

When would you choose !! over the safe-call ?. or the Elvis ?: operator, and what is the cost of choosing wrong?

level: middleimportance: must knowfreq 70%

basics

~20 s

Use !! only when you are certain a value can't be null and a crash is the right outcome if you're wrong. Use ?. or ?: when null is a real possibility you want to handle gracefully.

open as a page

How does chaining safe calls like a?.b?.c work, and what is the result type? What happens if b is null in the middle?

level: middleimportance: must knowfreq 80%

basics

~20 s

You can stack ?. through a chain. If any link is null, the whole chain stops and becomes null. The final result is nullable. So a?.b?.c is null if a, a.b, or a.b.c is null.

open as a page

Write an idiomatic expression that returns the length of `input: Any` if it is a `String`, and `-1` otherwise, using `as?`. Explain why `as?` is preferred over an `is` check plus `as` here.

level: middleimportance: must knowfreq 70%

basics

~10 s

Write (input as? String)?.length ?: -1. as? does the type test and conversion in one step and gives null on mismatch, so you don't need a separate is check followed by a cast.

open as a page

What is the precedence and associativity of the Elvis operator, and how does `a ?: b ?: c` evaluate?

level: middleimportance: should knowfreq 45%

basics

~20 s

Elvis is right-associative, so a ?: b ?: c means a ?: (b ?: c) — it falls through to the first non-null value left to right. It has low precedence, so combine with other operators carefully using parentheses.

open as a page

When is `x?.let { }` strictly better than `if (x != null) { }`, and what is one subtle gotcha when `x?.let` is paired with `?:`?

level: middleimportance: should knowfreq 65%

basics

~20 s

?.let is better when x is a mutable property the compiler won't smart-cast. The gotcha: if you write x?.let { ... } ?: fallback, the fallback also runs when the lambda itself returns null — not only when x is null.

open as a page

Why is chaining multiple !! on one line (a!!.b!!.c) considered bad practice, and how does it affect debugging?

level: middleimportance: should knowfreq 45%

basics

~10 s

If you put several !! on one line and it crashes, the error only tells you the line number, not which !! actually failed. Splitting them out makes the failure point obvious.

open as a page

How do you combine ?. with let and also (i.e. ?.let / ?.also) to run a block only when a value is non-null, and how do they differ?

level: middleimportance: should knowfreq 75%

basics

~20 s

Write value?.let { ... } to run the block only when value is not null. Inside, the value is non-null. ?.let returns the block's result; ?.also returns the original value and is used for side effects like logging.

open as a page

What is the difference between `x as String?` and `x as? String`? When `x` is `null` or the wrong type, how does each behave?

level: middleimportance: should knowfreq 40%

basics

~20 s

x as String? is an unsafe cast to a nullable type: it allows null but still throws if x is a non-null wrong type. x as? String is a safe cast: it returns null for both null input and wrong types, never throwing.

open as a page

Compare the Elvis operator with alternatives like ?.let, requireNotNull/checkNotNull, and !! for handling nullable values. When would you choose each?

level: seniorimportance: should knowfreq 50%

basics

~20 s

Use ?: to supply a default or to exit early on null. Use requireNotNull/checkNotNull to assert a value must exist with a clear message. Avoid !!, which throws an unhelpful NPE. Use ?.let to run code only when non-null.

open as a page

Compare `?.let` with `?.also`, `?.run`, and `?.apply` for null-guarded code. When would you pick each, and what does each return?

level: seniorimportance: should knowfreq 55%

basics

~20 s

All four run only on non-null receivers. let/also pass the value as it; run/apply expose it as this. let/run return the block's result; also/apply return the original receiver. Pick by what you need bound and what you want back.

open as a page

How do !! and platform types interact when calling Java from Kotlin, and why does Java interop drive overuse of !!?

level: seniorimportance: should knowfreq 40%

basics

~20 s

Java values whose nullability Kotlin can't see are 'platform types'. Kotlin lets you use them without forcing null checks, so developers reach for !! to convert them to non-null — sometimes hiding real nulls and causing crashes later.

open as a page

What is the result of a safe call on an extension function or a function returning Unit, and how does ?. interact with platform (Java) types?

level: seniorimportance: should knowfreq 45%

basics

~20 s

A safe call on a function that returns Unit gives Unit? — it's null when the receiver was null. ?. works on extension functions too. With Java values (platform types), the compiler doesn't force ?., so you must add it yourself to stay safe.

open as a page

Because of JVM type erasure, what does `value as? List<String>` actually check at runtime, and what is the implication for casting generic types safely?

level: seniorimportance: should knowfreq 48%

basics

~20 s

On the JVM the generic part is erased, so as? List<String> only checks that the value is some List, not that its elements are Strings. A List<Int> would pass the cast even though the elements are wrong.

open as a page

What are the evaluation semantics and pitfalls of the Elvis operator's right-hand side — side effects, double evaluation, and use in expressions returning Unit?

level: seniorimportance: nice to knowfreq 30%

basics

~20 s

The right side of ?: runs only when the left is null, so put side effects there carefully. The left side is evaluated once. Watch out when the right side returns Unit or has effects you didn't intend.

open as a page

What are the readability and correctness pitfalls of `?.let` in nested blocks, loops, and side-effecting code? How would you refactor an over-nested `let` chain?

level: seniorimportance: nice to knowfreq 40%

basics

~20 s

Deeply nested lets become a pyramid that's hard to read; a return inside one returns from the function, not the block; and ?.let swallows the null case silently. Often a guard clause with early returns or destructuring reads better.

open as a page

How does the Kotlin compiler lower a?.b?.c to JVM bytecode/Java, and what are the receiver-evaluation and short-circuit guarantees a senior should rely on?

level: seniorimportance: nice to knowfreq 30%

basics

~20 s

Under the hood, a?.b becomes a null check: evaluate the receiver once, if it's null give null, otherwise read the member. Chained calls become nested checks that stop at the first null. The receiver is only computed one time.

open as a page

When is !! genuinely justified, and how would you set a team policy and lint rules around it?

level: principalimportance: nice to knowfreq 25%

basics

~20 s

!! is fine in narrow cases where a value is guaranteed non-null but the compiler can't see it, like right after a check or a framework-initialized field. As a team, ban it by default and require a comment or a clearer assertion when it's truly needed.

open as a page

In a hot deserialization path you see heavy use of `as?` with Elvis defaults. How do you reason about correctness and cost, and when would you redesign away from runtime casting?

level: principalimportance: nice to knowfreq 24%

basics

~20 s

as? is a cheap type check, so cost is rarely the issue. The real concern is design: lots of as? means types are uncertain everywhere. Push validation to the boundary and use typed models so the core code never casts.

open as a page