Question

What the Elvis Operator Does in Kotlin

Question

I am trying to understand what ?: does in Kotlin, for example in this code:

val list = mutableList ?: mutableListOf()

I also want to understand why it can be rewritten like this:

val list = if (mutableList != null) mutableList else mutableListOf()

What does the ?: operator mean here, and why are these two versions equivalent?

Short Answer

By the end of this page, you will understand Kotlin's Elvis operator (?:), how it works with nullable values, and why it is equivalent to a simple if expression that checks for null. You will also see where it is commonly used in real Kotlin code and how to avoid common mistakes.

Concept

Kotlin has built-in null safety. One of the main ideas in Kotlin is that a variable can either be:

  • non-nullable: it must always contain a value
  • nullable: it may contain a value or null

The Elvis operator is written as ?:.

It means:

  • use the value on the left if it is not null
  • otherwise use the value on the right

So this code:

val list = mutableList ?: mutableListOf()

means:

  • if mutableList is not null, assign it to list
  • otherwise, create a new empty mutable list and assign that

This is equivalent to:

val list = if (mutableList != null) mutableList else mutableListOf()

The Elvis operator matters because handling null is extremely common in real programs. Data may be missing from:

  • API responses
  • databases
  • user input
  • configuration files
  • optional function arguments

Instead of writing a full if/else every time, Kotlin gives you a short, readable way to provide a fallback value.

Mental Model

Think of the Elvis operator like a backup plan.

  • First, try the value on the left.
  • If that value exists, use it.
  • If it is missing (null), fall back to the value on the right.

A simple analogy:

  • nickname ?: "Guest"

This means:

  • if the user has a nickname, use it
  • otherwise, use "Guest"

So ?: is like saying: "Use this, otherwise use that."

Take Quiz

Syntax and Examples

The basic syntax is:

val result = nullableValue ?: fallbackValue

Example 1: Default string

val name: String? = null
val displayName = name ?: "Anonymous"
println(displayName)

Output:

Anonymous

Because name is null, Kotlin uses the value on the right side.

Example 2: Your list example

val mutableList: MutableList<String>? = null
val list = mutableList ?: mutableListOf()
println(list)

Output:

[]

If mutableList already had a value, that existing list would be used instead.

Example 3: Equivalent if expression

val mutableList: MutableList<String>? = null

val list = if (mutableList != null) {
    mutableList
} else {
    mutableListOf()
}

This does the same thing. In Kotlin, if is an expression, so it can return a value.

Example 4: Elvis with safe calls

A very common pattern is combining ?. and ?::

val length = text?.length ?: 0

This means:

  • if text is not null, get text.length
  • otherwise, use 0

That is much shorter than:

val length = if (text != null) text.length else 0

Step by Step Execution

Consider this example:

val mutableList: MutableList<String>? = null
val list = mutableList ?: mutableListOf("A", "B")
println(list)

Step by step:

  1. mutableList is declared as MutableList<String>?

    • The ? means it may be null.
  2. mutableList is assigned null

    • So right now, it does not point to any list.
  3. Kotlin evaluates this expression:

    mutableList ?: mutableListOf("A", "B")
    
  4. Kotlin checks the left side: mutableList

    • Is it null?
    • Yes.
  5. Because the left side is null, Kotlin evaluates and uses the right side:

    mutableListOf("A", "B")
    
  6. list now refers to a new mutable list containing "A" and "B".

  7. println(list) prints:

    [A, B]
    

Now compare with a non-null value:

val mutableList: MutableList<String>? = mutableListOf("X")
val list = mutableList ?: mutableListOf("A", "B")
println(list)

Step by step:

  1. mutableList contains "X"
  2. Kotlin checks the left side of ?:
  3. It is not null
  4. Kotlin uses mutableList
  5. The right side is not needed
  6. Output is:
[X]

This is why the Elvis operator is efficient and readable: it only uses the fallback when needed.

Real World Use Cases

The Elvis operator is used whenever a value might be missing and you want a default.

Common use cases

1. Default values for user input

val username = inputName ?: "Guest"

If the user did not provide a name, use a safe default.

2. Safe API data handling

val title = apiResponse.title ?: "Untitled"

API fields are often nullable.

3. Optional configuration values

val port = envPort ?: 8080

If no environment value exists, use a standard port.

4. Empty collections instead of null

val items = response.items ?: emptyList()

This avoids repeated null checks later.

5. Fallback object creation

val session = currentSession ?: createNewSession()

If there is no current session, create one.

6. UI display defaults

val subtitle = article.subtitle ?: "No subtitle available"

This prevents null from reaching the UI.

Take Quiz

Real Codebase Usage

In real Kotlin projects, developers often use the Elvis operator in a few common patterns.

1. Guard clauses with early return

fun printName(name: String?) {
    val safeName = name ?: return
    println(safeName)
}

If name is null, the function returns immediately.

2. Throwing an error when a required value is missing

val token = config.token ?: throw IllegalStateException("Token is required")

This is very common when a value must exist.

3. Combining safe call and default

val itemCount = cart?.items?.size ?: 0

This safely navigates nested nullable values.

4. Replacing null collections with empty ones

val users = response.users ?: emptyList()

This makes later code simpler because you can iterate without checking for null.

5. Validation and fallback

val emailToUse = providedEmail ?: defaultEmail

Useful in service layers, controllers, and app setup code.

6. Constructor or mapping code

data class UserDto(val name: String?)
data class User(val name: String)

fun map(dto: UserDto): User {
    return User(name = dto.name ?: "Unknown")
}

This is common when converting external data into safer internal models.

Common Mistakes

1. Thinking ?: is a ternary operator

In some languages, ? : is a ternary conditional operator. Kotlin does not have that style of ternary operator.

For example, Java has:

condition ? value1 : value2

But Kotlin's ?: is specifically the Elvis operator, used for null fallback.

2. Using it on non-nullable values

Broken idea:

val name: String = "Sam"
val result = name ?: "Anonymous"

This is pointless because name can never be null.

Use Elvis when the left side is nullable:

val name: String? = null
val result = name ?: "Anonymous"

3. Forgetting that the right side is the fallback

Broken understanding:

val number: Int? = 5
val result = number ?: 0

result is 5, not 0, because the left side is not null.

4. Confusing null with empty values

The Elvis operator only checks for null, not empty strings or empty lists.

val text: String? = ""
val result = text ?: "default"
println(result)

Output:

The result is still the empty string, because "" is not null.

5. Overusing Elvis when if is clearer

Sometimes an if expression is easier to read, especially for more complex logic.

val result = if (user != null && user.isActive) user.name else "Guest"

If the condition is more than just null fallback, if may be the better choice.

6. Forgetting type compatibility

Both sides of the Elvis operator should produce compatible types.

Potential issue:

val value: String? = null
val result = value ?: 123

Kotlin will infer a broader type such as Any, which may not be what you want.

Prefer matching types:

val value: String? = null
val result = value ?: "123"

Comparisons

Elvis operator vs if expression

ApproachExampleBest for
Elvis operatorval name = input ?: "Guest"Simple null fallback
if expressionval name = if (input != null) input else "Guest"When you want the logic written explicitly

Both are equivalent for basic null checks.

Elvis operator vs safe call

OperatorExampleWhat it does
?.user?.nameAccesses a property only if the object is not null
?:user?.name ?: "Unknown"Provides a default if the left side is null

They are often used together.

Elvis operator vs !!

OperatorExampleBehavior
?:name ?: "Anonymous"Safely provides a fallback
!!name!!Forces non-null and may throw NullPointerException

In most cases, ?: is safer than !!.

Elvis operator vs empty checks

SituationExampleImportant note
Null checkname ?: "Guest"Only handles null
Empty string checkif (name.isNullOrEmpty()) "Guest" else nameHandles null and ""

Use the Elvis operator only when the problem is specifically null.

Take Quiz

Cheat Sheet

Quick syntax

val result = nullableValue ?: fallbackValue

Meaning

  • Use the left side if it is not null
  • Otherwise use the right side

Equivalent form

val result = if (nullableValue != null) nullableValue else fallbackValue

Common patterns

val name = input ?: "Guest"
val length = text?.length ?: 0
val users = response.users ?: emptyList()
val token = config.token ?: throw IllegalStateException("Missing token")
val item = value ?: return

Rules to remember

  • ?: is the Elvis operator
  • It is used for null fallback
  • It is not the same as a ternary operator from other languages
  • It only checks for null, not empty strings or empty collections
  • It works especially well with ?.

Good defaults

  • Strings: "Unknown", ""
  • Numbers: 0
  • Lists: emptyList() or mutableListOf()
  • Objects: a newly created default object

Watch out for

  • Using Elvis on a non-nullable value
  • Returning a fallback of the wrong type
  • Assuming it handles empty values

FAQ

What does ?: mean in Kotlin?

It is the Elvis operator. It returns the value on the left if that value is not null; otherwise, it returns the value on the right.

Is Kotlin ?: the same as the ternary operator in Java?

No. Kotlin does not have Java's condition ? a : b ternary operator. Kotlin's ?: is specifically for handling null values.

Why is mutableList ?: mutableListOf() the same as an if check?

Because both expressions do the same null test:

  • if mutableList is not null, use it
  • otherwise, create a new mutable list

When should I use the Elvis operator in Kotlin?

Use it when a value might be null and you want to provide a default, return early, or throw an exception.

Can I use the Elvis operator with throw or return?

Yes. This is common in Kotlin:

val user = currentUser ?: return
val token = config.token ?: throw IllegalStateException("Missing token")

Does the Elvis operator check for empty strings or empty lists?

No. It only checks for null. An empty string or empty list is still considered a real value.

Is the right side always evaluated?

It is evaluated only when the left side is null. That is why it works well for fallback creation.

Take Quiz

Mini Project

Description

Build a small Kotlin program that prepares user profile data for display. Some incoming values may be null, so you will use the Elvis operator to provide safe defaults. This demonstrates a very common real-world task: cleaning nullable data before using it in an application.

Goal

Create a Kotlin program that prints a safe, user-friendly profile summary even when some input fields are null.

Requirements

  • Create nullable variables for a user's name, age, and list of hobbies.
  • Use the Elvis operator to provide default values for missing data.
  • Print the final safe values in a readable format.
  • Use at least one example that combines ?. and ?:.
Take Quiz

Keep learning

Related questions

View more