Null Safety Best Practices
In this page:
Prefer Non-Null by Default
Design functions and classes so most properties and parameters are non-nullable, reserving ? only for cases where absence is truly meaningful, which keeps the rest of your code free of constant null checks.
Example: Prefer Non-Null by Default
data class Product(val name: String, val price: Double, val discountCode: String? = null)
fun main() {
val product = Product("Book", 15.0)
println("${product.name}: $${product.price}, discount=${product.discountCode ?: "none"}")
}
Login to try C/C++/Java/PHP code in the editor
Validate at the Boundary
When data comes from outside your program, such as parsed text or a network response, convert it into a proper non-null domain type as early as possible instead of passing raw nullable values deep into your logic.
Example: Validate at the Boundary
fun parseAge(input: String?): Int {
return input?.toIntOrNull() ?: error("Invalid or missing age: $input")
}
fun main() {
println("Age: ${parseAge("42")}")
}
Login to try C/C++/Java/PHP code in the editor
Avoid Nullable Collections
Returning an empty list instead of a nullable list means callers can safely iterate or check size without an extra null check, simplifying calling code considerably.
Note: An empty list is far easier to work with than null for representing 'no results'.
Example: Avoid Nullable Collections
fun findMatches(query: String, items: List<String>): List<String> {
return items.filter { it.contains(query) }
}
fun main() {
val results = findMatches("kt", listOf("main.kt", "readme.md"))
println("Found ${results.size} matches: $results")
}
Login to try C/C++/Java/PHP code in the editor
Reserve !! for Truly Impossible Nulls
Treat !! as a signal that something is architecturally wrong if it ever actually throws; use it only in the rare case where the surrounding logic guarantees non-null, and prefer safer operators everywhere else.
Example: Reserve !! for Truly Impossible Nulls
fun main() {
val cache = HashMap<String, String>()
cache["greeting"] = "Hello"
if ("greeting" in cache) {
println(cache["greeting"]!!)
}
}
Login to try C/C++/Java/PHP code in the editor
- Designing APIs that return nullable types when an empty collection or a sensible default would communicate the same information more safely.
- Sprinkling
!!throughout a codebase as a quick fix instead of addressing why a value might unexpectedly be null in the first place. - Not validating external data (network responses, user input) at the boundary of your program, letting nulls leak deep into business logic.
- Prefer non-nullable types by default; only mark something nullable when absence is a genuinely meaningful case.
- Validate and convert nullable external data (JSON, user input) into non-null domain types as early as possible.
- Use
?.,?:, and safe scope functions instead of!!in almost all situations. - Favor an empty collection over a nullable collection so callers do not need extra null checks just to iterate.
Chapter Quiz — Complete all 6 topics to unlock
0/6 topics done
Complete these topics first: