Kotlin Nullable Types
In many languages, variables can accidentally hold no value (called null), causing crashes at runtime. Kotlin treats null as a first-class concern — you must explicitly declare whether a variable can be null. This eliminates an entire class of bugs at compile time.
Non-Nullable vs Nullable
Non-Nullable (default):
val name: String = "Alice"
name = null ← ERROR! Cannot assign null to a non-nullable type
Nullable (add ? to the type):
var name: String? = "Alice"
name = null ← ALLOWED! The ? tells Kotlin null is expected
Declaring Nullable Variables
var username: String? = "Priya"
var email: String? = null // valid
var age: Int? = null // valid
var score: Double? = 99.5 // validThe Null Safety Problem Diagram
Without null safety (Java/Python):
String name = getUserName()
│
└── What if getUserName() returns null?
name.length ← NullPointerException CRASH at runtime!
With null safety (Kotlin):
val name: String? = getUserName()
name.length ← ERROR at compile time! Must handle null first.
Kotlin stops you before the crash happens.
Accessing Nullable Variables
You cannot directly call methods on a nullable type without handling the null case first:
var text: String? = "Hello"
// Direct access not allowed:
// println(text.length) ← ERROR
// Option 1: Null check with if
if (text != null) {
println(text.length) // safe here: Kotlin knows text is not null
}
// Option 2: Let Kotlin infer inside if block (smart cast)
if (text != null) {
println(text.uppercase()) // text auto-cast to String here
}Smart Cast
After a null check, Kotlin automatically treats the variable as non-nullable inside the safe block:
fun printLength(value: String?) {
if (value == null) {
println("Value is null")
return
}
// After the null return, value is smart-cast to String
println("Length: ${value.length}")
}
fun main() {
printLength("Kotlin") // Length: 6
printLength(null) // Value is null
}Nullable vs Non-Nullable: Summary
Type │ Can hold null? │ Example
───────────┼────────────────┼──────────────────
String │ No │ val s: String = "hello"
String? │ Yes │ var s: String? = null
Int │ No │ val n: Int = 42
Int? │ Yes │ var n: Int? = null
Practical Example: User Profile
data class UserProfile(
val name: String,
val phone: String?, // phone may not be provided
val bio: String? // bio is optional
)
fun printProfile(user: UserProfile) {
println("Name : ${user.name}")
if (user.phone != null) {
println("Phone: ${user.phone}")
} else {
println("Phone: Not provided")
}
if (user.bio != null) {
println("Bio : ${user.bio}")
} else {
println("Bio : No bio available")
}
}
fun main() {
val u1 = UserProfile("Alice", "+1-555-1234", "Developer and coffee lover")
val u2 = UserProfile("Bob", null, null)
printProfile(u1)
println("──────────────")
printProfile(u2)
}Output:
Name : Alice
Phone: +1-555-1234
Bio : Developer and coffee lover
──────────────
Name : Bob
Phone: Not provided
Bio : No bio available