Nullable and non-null types
In Java, any object reference can be null, and calling a method on one crashes with a NullPointerException — the most common production bug on the JVM. Kotlin splits every type in two. String can never hold null. String? (with a question mark) can hold a string or null. The compiler then refuses to let you call .length on a String? until you have dealt with the null case. The crash moves from runtime, in front of a user, to compile time, in front of you.
fun main() {
val name: String = "Asha" // never null
var nickname: String? = null // may be null
println(name.length)
println(nickname)
nickname = "Ash"
if (nickname != null) {
println(nickname.length) // allowed: checked just above
}
val middle: String? = null
println("middle is null? ${middle == null}")
}4
null
3
middle is null? trueDeclare val age: Int? = "31".toIntOrNull() and print age + 1. Read the compiler error, then fix it with an if check.
Assigning null to a non-null type
fun main() {
val name: String = null
println(name)
}Main.kt:2:24: error: null cannot be a value of a non-null type 'String'.String without a question mark is a promise that the value is always a real string. null breaks that promise, so the file does not compile.
If "no value" is a legitimate state, declare the type as String?. If it is not, give it a real value.
fun main() {
val name: String? = null
println(name)
}Calling a member on a nullable value
fun main() {
val name: String? = null
println(name.length)
}Main.kt:3:17: error: only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type 'String?'.This is the check that makes Kotlin null-safe. name might be null, and .length on null would crash, so the compiler insists you say what should happen in that case.
Use a safe call (name?.length, which gives null when name is null), add a default with ?:, or check with if (name != null) first. The next lessons cover all three.
fun main() {
val name: String? = null
println(name?.length ?: 0)
}