KotlinClassesBeginner

Null Safety (?, !!, ?., ?:, let)

Kotlin's type system helps eliminate NullPointerExceptions by distinguishing nullable and non-nullable types, providing operators and functions for safe handling.

Review the syntaxStudy the examplesOpen the coding app
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

1

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)
Output:
5 null null

A nullable `String?` can hold `null`. The safe call `?.` only accesses `length` if `name` is not `null`, otherwise it yields `null`.

2

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)
Output:
Guest user@example.com

The Elvis operator `?:` provides a fallback value if the expression on its left-hand side is `null`.

3

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}")
}
Output:
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.

4

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.")
}
Output:
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

1

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 null

Runtime support

Compatibility

JVMN/AKotlin 1.0+

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.