Scope-Limited Processing with let
In Kotlin, ?.let is a pattern that executes a lambda only when a nullable value is non-null. It lets you combine a null check and an action in a single expression. Inside the lambda, you can access the non-null value via the implicit parameter it.
Syntax
// ?.let skips execution when the value is null.
val name: String? = "Alice"
name?.let {
println(it.length) // Runs only if name is non-null.
}
// Capture the result (null if the value was null).
val result: Int? = name?.let { it.length * 2 }
// Comparison with an if null check
if (name != null) {
println(name.length) // Smart cast
}
// Equivalent using ?.let:
name?.let { println(it.length) }
Syntax overview
| Syntax | Description |
|---|---|
| value?.let { it } | Executes the lambda if value is non-null and returns the result; returns null otherwise. |
| value?.let { v -> } | Uses an explicit parameter name instead of the default it. |
| ?.let combined with ?: | Provides a default value when null (e.g., value?.let { ... } ?: default). |
| ?.also { it } | Similar to let, but returns the receiver itself instead of the lambda result. Useful for side effects. |
Sample code
data class User(val name: String, val email: String?)
fun findUser(id: Int): User? = if (id == 1) User("Alice", "alice@example.com") else null
fun main() {
// Basic ?.let usage
val name: String? = "Kotlin"
name?.let {
println("Length: ${it.length}") // Length: 6
println("Uppercase: ${it.uppercase()}") // Uppercase: KOTLIN
}
// Skipped when the value is null.
val nullName: String? = null
nullName?.let { println("This will not run.") }
println("Skipped null.") // Skipped null.
// Capture the result.
val length: Int? = name?.let { it.length * 2 }
println("Double the length: $length") // Double the length: 12
// Combine with ?: (Elvis operator).
val nullLength: Int = nullName?.let { it.length } ?: -1
println("Default when null: $nullLength") // -1
// Chain nested nullables.
val user: User? = findUser(1)
user?.let { u ->
u.email?.let { email ->
println("Email: $email") // Email: alice@example.com
}
}
// findUser(99) returns null, so this is skipped.
findUser(99)?.let { println("User: ${it.name}") }
println("Skipped non-existent user.")
// Process nullable elements in a list.
val names: List<String?> = listOf("Alice", null, "Bob", null, "Carol")
names.forEach { it?.let { name -> println(name) } }
}
Notes
?.let is one of the most commonly used null-check patterns in Kotlin. It is equivalent to if (value != null) { ... }, but because it is a scope function, you can assign its result to a variable or chain it with other calls.
The parameter inside the lambda defaults to it, but giving it an explicit name — such as ?.let { user -> ... } — improves readability when lambdas are nested.
For the basics of nullable types, see Nullable types / ?. operator. For scope functions in general, see let.
If you find any errors or copyright issues, please contact us.