NullPointerException has crashed more apps than anyone wants to count. If you’ve written Java, you know the pain. Kotlin fixes most of it at compile time, and the elvis operator is one of the cleanest tools in that toolkit.
So what is the Kotlin elvis operator, exactly? It’s a two-character shorthand (?:) that provides a default value when an expression evaluates to null. One line replaces an entire if-else block.
This guide covers how the elvis operator works, its syntax with real code examples, how it compares to null handling in Java and Swift, common mistakes that trip up developers, and where it shows up most in Android and Kotlin Multiplatform projects.
What Is the Kotlin Elvis Operator

The Kotlin elvis operator (?:) is a null-safety shorthand that returns the left-hand expression if it’s not null. If the left side evaluates to null, it returns whatever you put on the right side instead.
That’s the whole thing. One line of syntax, two possible outcomes.
Here’s what it looks like:
“ val result = nullableValue ?: "default" `
If nullableValue holds an actual value, result gets that value. If it's null, result gets “default”.
The name comes from a silly visual trick. Tilt your head to the left and look at ?: sideways. It kind of resembles Elvis Presley's hair. At least, that's what people say. Baeldung calls it the "null coalescing operator" as an alternate name, which is more accurate but way less fun.
The operator fits inside Kotlin’s broader null-safety type system, which distinguishes between nullable types (String?) and non-nullable types (String) at compile time. The Kotlin compiler won't let you assign null to a non-nullable variable, period.
But when you do work with nullable types, you need a way to handle the null case. That’s where the elvis operator steps in.
Without it, you’d write something like this:
` val length: Int if (userName != null) { length = userName.length } else { length = 0 } `
With it:
` val length = userName?.length ?: 0 `
Same outcome. Way less code. Took me a while to stop writing the if-else version out of Java habit, but once the elvis operator clicks, you don’t go back.
JetBrains built Kotlin with this kind of concise syntax as a core goal. The language was designed to cut boilerplate while keeping things safe. The elvis operator is a perfect example of that philosophy.
Kotlin Null Safety and Why the Elvis Operator Exists

NullPointerException is the single most common runtime error in Java applications. Harness (formerly OverOps) found that NullPointerException took the top spot in 70% of production Java environments they monitored.
That’s not a small number. And it’s exactly the problem Kotlin was built to fix.
How Kotlin’s Type System Handles Null
Kotlin’s type system splits every type into two categories at compile time:
- Non-nullable: String
,Int,Boolean. These can never hold null. The compiler blocks it.
- Nullable: String?
,Int?,Boolean?. These can hold null, but you must handle it explicitly.
This distinction means the compiler catches potential null-related issues before your code ever runs. According to Kotlin’s official documentation, null safety “ensures safer code by catching potential null-related issues at compile time rather than runtime.”
A JetBrains survey found that 62% of Kotlin developers specifically appreciated the language’s null-safety features for improving code maintainability.
Where the Safe Call Operator Falls Short
Kotlin gives you the safe call operator (?.) to access properties on nullable objects without crashing. If the object is null, the whole expression just returns null.
` val name: String? = null val length = name?.length // returns null, no crash `
That’s fine when you’re okay with getting null back. But what if you actually need a concrete value?
If you’re passing the result to a function that expects a non-nullable Int, returning null from name?.length doesn't cut it. You need a fallback.
The elvis operator fills that gap. It lets you chain a safe call and then provide a default value in one clean expression: name?.length ?: 0.
Google estimates that 70% of the top 1,000 apps on the Play Store are written in Kotlin, and JetBrains data suggests 95% of those apps include some Kotlin code. Most of those Android development projects rely heavily on the elvis operator for handling nullable Intent extras, Bundle values, and API responses.
Elvis Operator Syntax and Basic Usage

The full syntax is two characters: ?:
` val result = expression1 ?: expression2 `
If expression1 is not null, result gets the value of expression1. If it is null, result gets expression2.
Variable Assignment with Default Values
Basic nullable variable:
` val input: String? = null val output = input ?: "no input provided" // output = "no input provided" `
With a non-null value:
` val input: String? = "hello" val output = input ?: "no input provided" // output = "hello" `
The right side of ?: only gets evaluated when the left side is null. If input holds a real value, Kotlin skips the fallback entirely.
Combining with Safe Calls
This is where things get practical. You’ll see this pattern constantly in production Kotlin code:
` val displayName = user?.name ?: "Anonymous" `
The safe call (?.) handles the case where user itself might be null. The elvis operator handles the case where either user or user.name resolves to null.
You can also use it with function return values:
` fun getUsername(): String? = fetchFromDatabase()
val name = getUsername() ?: “Guest” `
At runtime, here’s what happens step by step:
- Kotlin evaluates the left-hand expression
- If the result is non-null, it returns that result immediately
- If the result is null, it evaluates and returns the right-hand expression
No magic under the hood. Baeldung decompiled elvis operator code to Java and confirmed it translates to standard null checking. No performance overhead, no hidden cost.
Elvis Operator with Return and Throw

This is the part that surprises people coming from other languages.
In Kotlin, both throw and return are expressions with the type Nothing. That means you can put them on the right side of the elvis operator.
Early Return with Elvis
Instead of writing guard clauses like this:
` fun processUser(user: User?) { if (user == null) return // rest of function } `
You can write:
` fun processUser(user: User?) { val validUser = user ?: return // validUser is now non-nullable } `
Two things happen here. The function exits early if user is null. And the Kotlin compiler smart-casts validUser as a non-nullable type for everything that follows.
This pattern shows up all the time in mobile application development, where you’re constantly dealing with nullable data from system callbacks.
Failing Fast with Throw
` val config = loadConfig() ?: throw IllegalStateException("Config missing") `
If the config can’t be loaded, the app fails immediately with a clear error message instead of silently passing null downstream.
This is a software development best practice that experienced teams follow. Fail loudly at the source of the problem rather than chasing mysterious NullPointerExceptions three layers deep in a stack trace.
According to CISQ data, poor software quality costs US companies upwards of $2.08 trillion annually. A significant chunk of that comes from null reference bugs that could have been caught earlier. The elvis-plus-throw pattern is one of the simplest ways to catch those problems at the right time.
Real Android Example
` val userId = intent.getStringExtra("USERID") ?: throw IllegalArgumentException("USERID required") `
Android’s getStringExtra returns a nullable String?. Without the elvis operator, you'd need a manual null check and a separate throw statement. With it, one line handles everything.
Elvis Operator vs Safe Call Operator vs the !! Operator

Kotlin gives you three tools for working with nullable types. They solve different problems, and picking the wrong one causes real headaches.
| Operator | Syntax | Behavior on Null | When to Use |
|---|---|---|---|
| Safe call | ?. | Returns null | When null is an acceptable result |
| Elvis | ?: | Returns a fallback value | When you need a concrete default |
| Non-null assertion | !! | Throws NullPointerException | Almost never |
The Safe Call Operator
?. accesses a property or calls a method only if the receiver isn't null. If it is null, the entire chain returns null instead of crashing.
` val city: String? = user?.address?.city `
That’s three potential null points handled in one expression. But the result type is String?, which means you still might be dealing with null downstream.
The Non-Null Assertion Operator
!! tells the compiler: "Trust me, this is not null." If you're wrong, it throws a NullPointerException at runtime.
` val name = nullableString!!.length // crashes if null `
Most Kotlin style guides discourage !! heavily. It defeats the entire purpose of compile-time null safety. The Kotlin documentation itself recommends using safer approaches like ?. or ?: instead.
There’s a reason NullPointerException was the number one error across 70% of Java production environments (Harness data). The !! operator reintroduces exactly that risk into Kotlin code.
Combining Safe Calls and the Elvis Operator in a Chain
The real power shows up when you chain them together:
` val cityName = user?.address?.city ?: "Unknown city" `
The safe calls navigate through potentially null objects. The elvis at the end catches the case where any part of the chain was null and provides a fallback.
One thing to watch for, though. Long chains get hard to read. I’ve seen expressions like a?.b?.c?.d?.e ?: default in production codebase files and they're not fun to debug. If your chain goes beyond two or three safe calls, consider breaking it into separate variables. Your future self will thank you.
Readability matters more than cleverness. Always.
Elvis Operator vs Null Handling in Java and Other Languages

Kotlin didn’t invent the concept of null coalescing. But it implemented it better than most.
Java’s Approach
Java has no elvis operator. You get two options:
Manual null checks:
` String name = user != null ? user.getName() : "default"; `
Optional wrapper (Java 8+):
` String name = Optional.ofNullable(user) .map(User::getName) .orElse("default"); `
Both work. Neither is as clean as user?.name ?: “default” in Kotlin.
The difference between Kotlin and Java on null handling is a big reason developers switch. Java will eventually get null-restricted types (Brian Goetz discussed this at JavaLand), but it’s not here yet.
Cross-Language Comparison
| Language | Operator | Key Difference |
|---|---|---|
| Kotlin | ?: | Works with return and throw on the right side |
| Groovy | ?: | Original source of the concept. Kotlin borrowed it |
| Swift | ?? | Nearly identical behavior, different symbol |
| TypeScript/JS | ?? | Nullish coalescing. Only checks null/undefined, not falsy values |
| C# | ?? | Similar to Kotlin’s, been around since C# 2.0 |
Kotlin’s version has one standout advantage over all the others. Because throw and return are expressions of type Nothing in Kotlin, you can use them on the right side of ?:. Try doing val x = y ?? return in Swift or TypeScript. It won't compile.
Groovy is where Kotlin got the idea. JetBrains has acknowledged this. The Apache Groovy language had the elvis operator for years before Kotlin existed, and the syntax is identical: ?:.
For teams working on cross-platform app development or maintaining code across multiple languages, knowing these parallels helps. You’ll recognize the pattern even when the syntax differs.
Stack Overflow’s 2024 Developer Survey ranked Kotlin among the top 10 most-loved languages, and its approach to null safety is consistently cited as one of the reasons. The elvis operator is a small part of that, but it’s one of the first things developers notice when switching from Java.
Common Mistakes with the Elvis Operator
The elvis operator is simple. Two characters: ?:. But developers still trip over it in ways that cause real bugs.
Confusing It with a Ternary Operator
Kotlin has no ternary operator. Period.
People coming from Java, C#, or JavaScript expect condition ? valueA : valueB to work. It doesn't compile. Kotlin uses if as an expression instead:
` val max = if (a > b) a else b `
The elvis operator is not a ternary replacement. It only checks for null, not for arbitrary boolean conditions. Mixing up these two concepts is one of the most common beginner mistakes in Kotlin null handling.
Operator Precedence Surprises
This one bites experienced developers too. The elvis operator has lower precedence than arithmetic operators but higher than comparison operators.
` // What you think happens: (value ?: 0) > threshold
// What actually happens: value ?: (0 > threshold) `
Add parentheses when mixing ?: with comparisons or arithmetic. Don't trust your memory on operator precedence. Even the Kotlin documentation warns that precedence behavior with ?: can create subtle bugs.
Hiding Bugs with Silent Defaults
Danny Preussler, a Google Developer Expert, wrote about a tricky pattern where the elvis operator executes both sides of an expression when combined with scope functions like let.
` data?.updateData(data) ?: run { showLoadingSpinner() } `
If updateData() returns null, the run block fires too. The elvis operator evaluates the entire left side, including the return value of the last expression in a chain.
This isn’t an if/else. It checks whether the final resolved value is null, not whether the original object was null.
Nesting Elvis Operators
You can chain multiple elvis operators:
` val result = a ?: b ?: c ?: "fallback" `
That’s readable enough. But I’ve seen code in production where developers nest them inside string templates or complex expressions, and it becomes a puzzle. If your elvis chain goes beyond two levels, extract the logic into a named function. Code refactoring exists for exactly these situations.
Elvis Operator in Android and Kotlin Multiplatform Projects

The elvis operator shows up more in Android apps than almost anywhere else. Android APIs return nullable types constantly, and the elvis operator is how most Kotlin developers handle that.
Working with Nullable Intent Extras and Bundles
The pattern:
` val userId = intent.getStringExtra("USER_ID") ?: "guest" val retryCount = intent.getIntExtra("RETRY", -1) `
Android’s getStringExtra() returns String?. Without the elvis operator, you'd need a separate null check and variable assignment for every single extra you pull from an Intent.
As of May 2024, 40% of the top 1,000 apps on Google Play use Jetpack Compose (Wikipedia data). Nearly all of them interact with nullable system APIs where the elvis operator provides the fallback.
Jetpack Compose UI State Fallbacks
Compose components frequently need default values when state hasn’t loaded yet:
` @Composable fun UserProfile(viewModel: UserViewModel) { val user = viewModel.user.collectAsState().value Text(text = user?.displayName ?: "Loading...") } `
The ?: here keeps the UI from showing blank content while data loads. Google rewrote parts of the Play Store app with Compose, reporting that UI code required up to 50% less code compared to the previous approach.
Meta built Threads in five months using Jetpack Compose. That speed partly comes from patterns like this, where nullable state gets a clean fallback in one line.
Kotlin Multiplatform Shared Logic
Kotlin Multiplatform lets teams share business logic across Android and iOS while keeping the UI native to each platform.
JetBrains Developer Ecosystem data shows KMP usage jumped from 7% to 18% between 2024 and 2025. Companies like McDonald’s, Forbes, and Netflix use it in production.
In shared KMP modules, platform-specific APIs often return nullable types because the shared code can’t guarantee what each platform provides. The elvis operator handles those platform boundaries:
` // Shared module expect fun getPlatformCachePath(): String?
// Usage in shared logic val cachePath = getPlatformCachePath() ?: “/tmp/default” `
Forbes shares over 80% of logic across iOS and Android through KMP, and organizations adopting this approach report up to a 30% cut in development and maintenance costs.
Server-Side Kotlin with Ktor
Parsing request parameters on the server side is another spot where the elvis operator gets heavy use:
` val page = call.parameters["page"]?.toIntOrNull() ?: 1 val limit = call.parameters["limit"]?.toIntOrNull() ?: 20 `
Query parameters are always nullable. They might not exist, or they might not be valid integers. The safe call, toIntOrNull(), and the elvis operator work together to provide a clean default in a single expression.
Kotlin’s use in back-end development with frameworks like Ktor and Spring Boot follows the same null-safety patterns that make it popular on Android.
When Not to Use the Elvis Operator
Not every null situation calls for ?:. Sometimes it makes code worse.
When Scope Functions Are a Better Fit
If you need to do something with a non-null value rather than just provide a fallback, let is usually cleaner:
` // Elvis: not ideal for side effects val result = user?.name ?: run { logMissingUser(); "default" }
// let: clearer intent user?.name?.let { sendWelcomeEmail(it) } `
Kotlin’s scope functions (let, run, also, apply, with) are inline functions with zero runtime overhead, according to Kotlin documentation. They exist specifically for cases where you want to operate on an object within a temporary scope.
The elvis operator answers “what value should I use if this is null?” Scope functions answer “what should I do with this value if it’s not null?” Different questions, different tools.
When Nullable Types Signal a Design Problem
Sprinkling ?: everywhere can mask a deeper issue. If you're adding elvis operators to every other line, your data model probably has too many nullable fields.
| Situation | Better Approach |
|---|---|
| Every field in a class is nullable | Use non-nullable types with required constructors |
| Function returns null for “not found” | Use sealed classes or Result type |
| Config values might be missing | Validate at startup, fail fast with require() |
| API response fields are all String? | Map to domain models with proper nullability |
Kotlin’s data classes let you define exactly which fields are nullable and which aren’t. Use them to push null checks to the boundary of your system instead of scattering elvis operators throughout your logic.
When Default Values Have Side Effects
The right side of ?: only evaluates when the left side is null. That's usually fine. But if the fallback expression creates objects, hits a database, or triggers network calls, you might not want that happening silently.
` // This creates a new User object every time name is null val displayName = user?.name ?: createDefaultUser().name `
If the default is expensive, make it explicit. Use an if block so the cost is visible to whoever reads the code later. Readability beats cleverness every time, especially in a software development process where multiple people touch the same code.
When Chained Operators Hurt Readability
There’s a point where one-liners stop being helpful. This compiles fine:
` val x = a?.b?.c?.d?.e?.f ?: g?.h ?: "default" `
But good luck debugging it when something breaks. A code review would (and should) flag this immediately.
Break complex chains into intermediate variables. Name them clearly. The compiler doesn’t care, but the person reading your code at 2 AM will.
FAQ on What Is The Kotlin Elvis Operator
What does the Kotlin elvis operator do?
The elvis operator (?:) returns the left-hand expression if it's not null. If it is null, it returns the right-hand expression instead. It's a concise alternative to writing full if-else null checks in your Kotlin code.
Why is it called the elvis operator?
Tilt the ?: symbol sideways and it resembles Elvis Presley's hair. That's the whole reason. The more formal name is the null coalescing operator, but "elvis operator" stuck because it's easier to remember.
Is the elvis operator the same as a ternary operator?
No. Kotlin has no ternary operator. The elvis operator only checks for null, not arbitrary boolean conditions. For general conditional logic, Kotlin uses if as an expression that returns a value directly.
Can you use throw or return with the elvis operator?
Yes. In Kotlin, throw and return are expressions of type Nothing. You can place them on the right side of ?: for early function exits or to fail fast when a value is unexpectedly null.
What is the difference between the safe call and the elvis operator?
The safe call operator (?.) returns null when the receiver is null. The elvis operator (?:) provides a fallback value instead of null. They're often chained together: user?.name ?: “Guest”.
Does the elvis operator exist in Java?
No. Java has no built-in elvis operator. You’d use Optional.orElse() or a standard ternary expression for similar behavior. This is one of the key differences between Kotlin and Java regarding null safety.
How does the elvis operator handle operator precedence?
The elvis operator has lower precedence than arithmetic operators but higher than comparison operators. Mixing ?: with comparisons without parentheses can produce unexpected results. Always add parentheses when combining it with other operators.
Can you chain multiple elvis operators together?
Yes. You can write a ?: b ?: c ?: “default” and Kotlin evaluates left to right. The first non-null value wins. Keep chains short though. Beyond two or three levels, readability drops fast.
When should you avoid using the elvis operator?
Avoid it when scope functions like let or run are a better fit, when the default value triggers expensive side effects, or when too many nullable fields suggest a design problem with your data model.
Do other programming languages have an elvis operator?
Groovy uses the same ?: syntax. Swift and TypeScript use ?? for null coalescing, which works similarly. Kotlin's version is unique because it supports throw and return on the right side.
Understanding what is the Kotlin elvis operator comes down to one idea: provide a fallback value when something is null, in one clean expression. Two characters (?:) replace entire if-else blocks and guard clauses across your Kotlin codebase.
It pairs naturally with the safe call operator for chaining nullable property access. It works with throw and return` because Kotlin treats them as expressions of type Nothing. And it shows up in nearly every Android project, Ktor server app, and Kotlin coroutines workflow where nullable types are part of daily work.
Use it when a default value makes sense. Skip it when scope functions, sealed classes, or a redesign of your nullable data model would serve you better.
The elvis operator won’t fix bad architecture. But for straightforward null handling in software development, it’s one of the best tools Kotlin gives you.



