Lesson 4 / 25
Nullable Types and Safe Operators
String versus String?, ?., ?: and !!.
Null is part of the type
In Kotlin a String can never hold null; a String? can. The compiler refuses to call members on a nullable value directly. The safe call a?.length returns null if a is null. The elvis operator a ?: default supplies a fallback (it can also return or throw). The not-null assertion a!! converts to non-null and throws a NullPointerException if the value is null, so use it rarely. After if (a != null), the compiler smart casts a to the non-null type inside the branch, as long as it is a local val or a value it can prove does not change.
Nulls become compile-time errors
Kotlin separates nullable and non-null types and narrows types automatically after checks.
Handling a missing value
Safe call, elvis and smart cast.
data class User(val name: String, val email: String?)
fun emailDomain(user: User): String {
val email = user.email ?: return "no email" // elvis with early return
return email.substringAfter("@") // email is String here
}
fun nameLength(name: String?): Int {
if (name != null) {
return name.length // smart cast to String
}
return 0
}
fun shout(text: String?): String? = text?.uppercase() // null stays nullTreat !! as a code smell
Each !! is a place where you told the compiler "trust me". Prefer ?: with a sensible default, an early return, or requireNotNull(x) { "message" } which throws with a clear message.
Quick check: What does `user?.email ?: "none"` evaluate to when `user` is null?
- null
- "none"
- It throws NullPointerException
- An empty string
Answer
"none" — The safe call yields null and elvis supplies the fallback.