ProgrammingAndroid Developer

What is the Elvis operator (?:) in Kotlin, how and why to use it? What nuances and pitfalls can arise when using it?

Pass interviews with Hintsage AI assistant

Answer.

Background:

The Elvis operator (?:) appeared in Kotlin as a concise and safe way to handle nullable values. It got its name because of its resemblance to Elvis Presley's hairstyle when viewed from the side. The goal is to eliminate the boilerplate code of the form if (a != null) a else b and make daily development more convenient.

Problem:

Direct access to a value that may be null leads to a runtime error (NullPointerException). Therefore, a tool is needed to elegantly substitute default values when a variable turns out to be null.

Solution:

The Elvis operator applies to nullable types. If the expression to the left of the operator is not null, it returns that expression; otherwise, it returns the expression to the right. This makes the code more compact and safe.

Code example:

fun getLength(str: String?): Int { return str?.length ?: 0 } val result = getLength(null) // result == 0 val result2 = getLength("Hello") // result2 == 5

Key features:

  • Allows avoiding explicit null checks
  • Can be used to throw exceptions
  • Perfectly combined with nullable types, expressions, and functions with side effects

Tricky questions.

What happens if an expression with a side effect is to the right of the Elvis operator? Does it always get executed?

No! The expression to the right is only evaluated if the left side is null. This can be crucial if the function has side effects or "expensive" computations.

Code example:

var called = false val x: String? = "test" val y = x ?: run { called = true; "default" } // called will be false, because run won't even execute

Can the Elvis operator be used to throw exceptions?

Yes, in Kotlin you can write like this:

fun getLengthStrict(str: String?): Int = str?.length ?: throw IllegalArgumentException("str is null")

If str is null, an exception will be thrown. This is a convenient data validation mechanism.

Can multiple Elvis operators be "chained" together?

Yes, this is a common approach for fallbacks:

val name = fromDatabase ?: fromCache ?: "Unknown"

This expression will return the first NON-null value or the string "Unknown".

Common mistakes and anti-patterns

  • Complex long chains of Elvis operators that hinder code readability
  • Ignoring the side effects of the expression on the right, which can lead to unexpected behavior
  • Using Elvis when an explicit null check is needed and should be handled differently

Real-life example

Negative case

Multilevel nesting of null-checks via Elvis:

val title = a?.b?.c?.d?.e ?: defaultTitle

Pros:

  • Concise for simple logic

Cons:

  • Poor readability
  • Difficult to debug if the problem is unclear

Positive case

Explicit decomposition step by step with clear variable names:

val deepValue = a?.b val deeperValue = deepValue?.c?.d ?: default

Pros:

  • Increased readability
  • Easier to add additional checks or logging

Cons:

  • Slightly more verbose; may seem "unnecessary" steps to beginners