Language
日本語
English

Caution

JavaScript is disabled in your browser.
This site uses JavaScript for features such as search.
For the best experience, please enable JavaScript before browsing this site.

Kotlin Dictionary

  1. Home
  2. Kotlin Dictionary
  3. Scope-Limited Processing with let

Scope-Limited Processing with let

Since: Kotlin 1.0(2016)

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

val name: String? = "sample_data"
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

SyntaxDescription
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

sample_let_null_check.kt
data class User(val name: String, val email: String?)

fun findUser(id: Int): User? = if (id == 1) User("user_1", "user_1@wp-p.info") 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: user_1@wp-p.info
        }
    }

    // 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("item_a", null, "item_b", null, "item_c")
    names.forEach { it?.let { name -> println(name) } }
}
let_null_check.kt
kotlinc let_null_check.kt -include-runtime -d let_null_check.jar
java -jar let_null_check.jar
Length: 6
Uppercase: KOTLIN
Skipped null.
Double the length: 12
Default when null: -1
Email: user_1@wp-p.info
Skipped non-existent user.
item_a
item_b
item_c

Common Mistakes

Mistake 1: The return value of ?.let is a nullable type (e.g., Int?), so you cannot use it directly in arithmetic.

mistake_let_nullable_return.kt
fun main() {
    val nullName: String? = null
    val len = nullName?.let { it.length } // len is Int?
    // println(len + 1) // Compile error: operator + is not defined for Int?
}

Use ?: to provide a default value and get a non-null type.

fix_let_nullable_return.kt
fun main() {
    val nullName: String? = null
    val safeLen: Int = nullName?.let { it.length } ?: 0
    println("Length: $safeLen") // Length: 0
}

Mistake 2: Omitting the parameter name in nested ?.let calls causes multiple its to clash and makes the code hard to read.

mistake_let_it_nested.kt
fun main() {
    val name: String? = "sample_data"
    // Nested it clashes and is confusing
    name?.let { it?.let { it.uppercase() } }
}

Give explicit parameter names when nesting lambdas.

fix_let_it_nested.kt
fun main() {
    val name: String? = "sample_data"
    name?.let { n -> println(n.uppercase()) }
}

Mistake 3: let returns the result of the last expression, while also returns the receiver itself. Mixing them up produces an unexpected type.

mistake_let_vs_also.kt
fun main() {
    val name: String? = "item_a"
    val result1 = name?.let { it.length } // Int?  (transformed value)
    val result2 = name?.also { it.length } // String? (original value, not transformed)
    println("let: $result1") // let: 6
    println("also: $result2") // also: item_a
}

The command looks like this:

kotlinc mistake_let_vs_also.kt -include-runtime -d mistake_let_vs_also.jar
java -jar mistake_let_vs_also.jar
let: 6
also: item_a

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 .