Null Safety (?, !!, ?., ?:, let)
Kotlin's type system helps eliminate NullPointerExceptions by distinguishing nullable and non-nullable types, providing operators and functions for safe handling.
val nullableVar: String? = null
nullableVar?.length
nullableVar ?: "default"
nullableVar!!.length
nullableVar?.let { it.uppercase() }This static page keeps the syntax and examples indexed for search, while the coding app handles interactive exploration and saved references.
What it does
Overview
Kotlin's type system helps eliminate NullPointerExceptions by distinguishing nullable and non-nullable types, providing operators and functions for safe handling.
Kotlin's null safety is a core feature designed to prevent the infamous `NullPointerException` (NPE) at compile time, making code more robust and reliable. By default, all types in Kotlin are non-nullable, meaning a variable of type `String` cannot hold a `null` value. To allow a variable to hold `null`, you must explicitly declare it as nullable by appending a question mark (`?`) to its type (e.g., `String?`). Once a type is nullable, Kotlin forces you to handle the `null` case before accessing its members. This is achieved through several operators and constructs: - **Safe call operator (`?.`)**: Calls a method or accesses a property only if the object is not null; otherwise, it evaluates to `null`. - **Elvis operator (`?:`)**: Provides a default value if the expression on its left-hand side is `null`. - **Non-null assertion operator (`!!`)**: Converts any value to a non-nullable type, throwing an `NPE` if the value is `null`. This should be used sparingly and only when you are absolutely certain a value won't be `null` at runtime. - **Safe casts (`as?`)**: Attempts to cast to a type, returning `null` on failure instead of throwing a `ClassCastException`. - **`let` scope function**: Executes a block of code only if the object is not `null`, referring to it as `it` within the block. These features collectively encourage developers to explicitly consider and handle `null` possibilities, leading to safer and more predictable code. The compile-time checks are a significant advantage over languages that rely solely on runtime checks for nullability. The time complexity for these operations is generally O(1), as they involve simple checks and conditional execution.
Quick reference
Syntax
val nullableVar: String? = null
nullableVar?.length
nullableVar ?: "default"
nullableVar!!.length
nullableVar?.let { it.uppercase() }
See it in practice
Examples
Nullable type declaration and safe call operator
var name: String? = "Alice"
println(name?.length) // Safe call
name = null
println(name?.length) // Evaluates to null
val address: String? = null
val streetLength = address?.length
println(streetLength)5 null null
A nullable `String?` can hold `null`. The safe call `?.` only accesses `length` if `name` is not `null`, otherwise it yields `null`.
Elvis operator for default values
val username: String? = null
val displayName = username ?: "Guest"
println(displayName)
val email: String? = "user@example.com"
val displayEmail = email ?: "No email provided"
println(displayEmail)Guest user@example.com
The Elvis operator `?:` provides a fallback value if the expression on its left-hand side is `null`.
Non-null assertion operator (use with caution)
var data: String? = "Hello"
println(data!!.uppercase())
data = null
try {
println(data!!.uppercase())
} catch (e: NullPointerException) {
println("Caught NPE: ${e.message}")
}HELLO Caught NPE: data must not be null
The `!!` operator asserts that a value is non-null. If it's `null`, it throws an `NPE`. Use only when you are absolutely sure it won't be null.
Using let for safe execution on non-null values
val message: String? = "Hello Kotlin"
message?.let {
println("Message length: ${it.length}")
println("Message in uppercase: ${it.uppercase()}")
}
val emptyMessage: String? = null
emptyMessage?.let {
println("This won't be printed.")
}Message length: 12 Message in uppercase: HELLO KOTLIN
The `let` scope function executes its lambda block only if the receiver object (`message`) is not null. Inside the block, the non-null value is referred to by `it`.
Debug faster
Common Errors
NullPointerException
Cause: Overuse or misuse of the non-null assertion operator (`!!`), asserting a value is non-null when it actually is `null` at runtime.
Fix: Avoid `!!` unless you have a strong guarantee (e.g., from external code or prior checks) that the value will not be `null`. Prefer safe calls (`?.`), Elvis operator (`?:`), or `if (x != null)` checks with smart casts.
var user: User? = null
val name = user!!.name // Throws NPE if user is nullRuntime support
Compatibility
Source: Kotlin Documentation
Common questions
Frequently Asked Questions
Kotlin's type system helps eliminate NullPointerExceptions by distinguishing nullable and non-nullable types, providing operators and functions for safe handling.
NullPointerException: Avoid `!!` unless you have a strong guarantee (e.g., from external code or prior checks) that the value will not be `null`. Prefer safe calls (`?.`), Elvis operator (`?:`), or `if (x != null)` checks with smart casts.