ProgrammingAndroid Developer

How does the safe call operator ('?.') work in Kotlin, and when should it be used for working with nullable types?

Pass interviews with Hintsage AI assistant

Answer.

The safe call operator '?.' is one of the key tools for dealing with null values in Kotlin and appears as an evolution of the language ideas aimed at increasing safety and ease of working with potentially absent values.

Background: In Java, null values often become a source of errors (NullPointerException). Kotlin introduced a strict type system with explicit differentiation between nullable and non-nullable variables and accompanied this introduction with tools for their convenient use.

Problem: How to avoid NullPointerException when dealing with objects that might be null, without sacrificing code readability and conciseness?

Solution: The '?.' operator allows you to delicately access properties and methods of nullable variables: if the object is not null, the call is made; if it is null, null is returned (or necessary logic is followed).

Code example:

val user: User? = getUser() val name = user?.name // if user != null, user.name will be returned, otherwise null user?.printInfo() // if user != null, printInfo() will be called

Key features:

  • Avoids explicit checks like if (object != null) { ... }
  • A compact and convenient alternative to nested checks
  • Can be used together with let and the Elvis operator to handle null cases

Trick Questions.

Can the safe call operator '?.' be used on the left side of an assignment?

No. The '?.' operator cannot be used for safely setting a property or variable's value; it is only used for accessing or calling. The following is incorrect:

user?.name = "Alex" // Compilation error

Setting properties can be safely executed through an explicit check:

user?.let { it.name = "Alex" }

What does a chain of safe call operators return upon the first encounter with null?

As soon as one of the elements in the '?.' chain is null, the result of the expression becomes null, and further safe calls are not executed.

Example:

user?.address?.zipCode // if user or address == null, the result is null

Can safe call '?.' be used with functions that return Unit?

Yes, the call will still occur only if the object is not null, and it will return null instead of Unit if the object is null.

Example:

user?.clearData() // if user == null, nothing will happen

Common mistakes and anti-patterns

  • Using '!!' after '?.' – the meaning of the safe call is lost, potentially leading to NullPointerException.
  • Constructing long chains of '?.' without handling the null case at the output – the result may be inconvenient for further processing without additional checks.

Real-life examples

Negative case

A developer uses '!!' where the object could be null, after a long chain of safe calls:

val country = user?.address?.city?.country!!

Pros:

  • It's concise.

Cons:

  • Any null in the chain will cause the application to crash with NullPointerException.

Positive case

Safe call is used alongside the Elvis operator to return a default value:

val country = user?.address?.city?.country ?: "Unknown"

Pros:

  • Protection against errors, predictable behavior, readability.

Cons:

  • It may be difficult to diagnose at which stage in the chain null occurred without additional logs.