Kotlin Safe Call Chains
A safe call chain follows links that may hold null without crashing. One null link makes the whole chain give null.
Two safe calls in one chain
The chain reads the address and then the city. A null holder makes the whole chain give null.
data class Address(val city: String?)
data class Person(val name: String, val address: Address?)
fun main() {
val person: Person? = Person("Ana", Address("Oslo"))
println(person?.address?.city)
val missing: Person? = null
println(missing?.address?.city)
}A chain that stops in the middle
The address link holds null here. The rest of the chain never runs, and the result is null.
data class Address(val city: String?)
data class Person(val name: String, val address: Address?)
fun main() {
val person = Person("Ana", null)
println(person.address?.city?.length)
println(person.address?.city?.length ?: -1)
}A let block at the end of a chain
The let block runs for the chain with a real city. The other chain gives null, so its let block stays silent.
data class Address(val city: String?)
data class Person(val name: String, val address: Address?)
fun main() {
val person: Person? = Person("Ana", Address("Oslo"))
person?.address?.city?.let { println("City $it") }
val missing: Person? = Person("Bo", null)
missing?.address?.city?.let { println("City $it") }
println("done")
}A chain with an Elvis fallback
The Elvis operator gives a fallback word when the chain gives null. A real city passes through unchanged.
data class Address(val city: String?)
data class Person(val name: String, val address: Address?)
fun main() {
val person: Person? = null
println(person?.address?.city ?: "unknown city")
val other: Person? = Person("Ana", Address("Oslo"))
println(other?.address?.city ?: "unknown city")
}Example
data class Address(val city: String?)
data class Person(val name: String, val address: Address?)
fun main() {
val people = listOf(Person("Ana", Address("Oslo")), Person("Bo", null), Person("Cy", Address(null)))
for (person in people) {
println(person.address?.city?.length ?: 0)
}
val first: Person? = people.firstOrNull()
first?.address?.city?.let { println(it.uppercase()) }
}Key points
- The safe call operator ?. reads a property only when the value before it is not null.
- Two or more safe calls can link together in one expression.
- The chain gives null as soon as one link holds null.
- Later links in a stopped chain never run.
- An Elvis fallback can stand in for the null result of a chain.
- A let block at the end of a chain runs only when the chain gives a real value.
In this example, the loop prints the city length for the first holder and 0 for the other two. Both other chains hit a null link, so the Elvis fallback gives 0 each time. The final chain reaches a real city, so the let block prints the city in uppercase.
Try it Yourself
Edit the code, then press Run.
Running is simulated ยท Kotlin Playground
Exercise
A holder holds null for its address link. What does holder.address?.city?.length give?