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:
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
A developer uses '!!' where the object could be null, after a long chain of safe calls:
val country = user?.address?.city?.country!!
Pros:
Cons:
Safe call is used alongside the Elvis operator to return a default value:
val country = user?.address?.city?.country ?: "Unknown"
Pros:
Cons: