Skip to content

Kotlin Lambda 表达式详解 🎯 ​

Android 面试必考 Kotlin Lambda 表达式,包含 Lambda 语法、匿名函数、接收者的 Lambda、Lambda 捕获、性能优化等核心知识点


目录 ​

  1. Lambda 语法
  2. Lambda 与匿名函数
  3. 接收者的 Lambda
  4. Lambda 捕获
  5. Lambda 性能
  6. 面试考点汇总

1. Lambda 语法 ​

1.1 基础语法 ​

Lambda 表达式是匿名函数的简洁表示形式:

kotlin
// 完整语法:{ 参数 -> 函数体 }
val sum = { a: Int, b: Int -> a + b }

// 类型推断(推荐)
val sum: (Int, Int) -> Int = { a, b -> a + b }

// 单个参数可以使用 it(省略参数声明)
val double: (Int) -> Int = { it * 2 }

// 无参数
val greet: () -> String = { "Hello" }

// 无返回值
val printHello: () -> Unit = { println("Hello") }

// 多行 Lambda
val complex = { x: Int, y: Int ->
    val sum = x + y
    val product = x * y
    sum + product  // 最后一行是返回值
}

1.2 Lambda 的参数 ​

kotlin
// 多个参数
val sum: (Int, Int) -> Int = { a, b -> a + b }

// 带类型声明
val sum2 = { a: Int, b: Int -> a + b }

// 使用 it(单个参数)
val numbers = listOf(1, 2, 3)
numbers.forEach { println(it) }

// 自定义参数名(更清晰)
numbers.forEach { number ->
    println("Number: $number")
}

// 多个参数必须命名
val pairs = listOf(1 to "a", 2 to "b")
pairs.forEach { (num, str) ->
    println("$num: $str")
}

// 忽略不需要的参数
listOf(1, 2, 3).forEach { _ ->
    println("Item")
}

1.3 Lambda 的返回值 ​

kotlin
// 隐式返回(最后一行)
val sum: (Int, Int) -> Int = { a, b ->
    a + b  // 自动返回
}

// 显式返回
val sum2: (Int, Int) -> Int = { a, b ->
    return@sum2 a + b
}

// 带标签的返回(用于嵌套 Lambda)
fun nestedExample() {
    val list = listOf(1, 2, 3)
    
    list.forEach {
        if (it == 2) {
            return@forEach  // 只返回当前 Lambda
        }
        println(it)
    }
    
    println("Done")  // 会继续执行
}

// 从外部函数返回(需要 inline)
inline fun <T> List<T>.findAndReturn(predicate: (T) -> Boolean): T? {
    for (element in this) {
        if (predicate(element)) {
            return element  // 非局部返回
        }
    }
    return null
}

1.4 Lambda 作为参数 ​

kotlin
// 尾随 Lambda(最后一个参数是函数)
fun <T> List<T>.customMap(transform: (T) -> Int): List<Int> {
    return this.map(transform)
}

// 调用 - Lambda 放在括号外
val numbers = listOf(1, 2, 3)
val result = numbers.customMap {
    it * 2
}

// 只有 Lambda 参数时,括号可以省略
fun runBlock(block: () -> Unit) {
    block()
}

// 调用
runBlock {
    println("Hello")
}

// 多个参数时
fun <T> List<T>.process(
    prefix: String,
    transform: (T) -> String
): List<String> {
    return this.map { "$prefix${transform(it)}" }
}

// 调用
val result = numbers.process("Number: ") {
    it.toString()
}

1.5 Lambda 的类型推断 ​

kotlin
// 上下文类型推断
val sum: (Int, Int) -> Int = { a, b -> a + b }

// 作为参数时推断
fun operate(a: Int, b: Int, operation: (Int, Int) -> Int): Int {
    return operation(a, b)
}

operate(3, 4) { a, b -> a + b }  // 推断为 (Int, Int) -> Int

// 返回值推断
fun getOperation(): (Int, Int) -> Int {
    return { a, b -> a + b }  // 推断返回类型
}

// 属性推断
class Calculator {
    var operation: (Int, Int) -> Int = { a, b -> a + b }
}

1.6 Lambda 的实际应用 ​

kotlin
// 1. 集合操作
val numbers = listOf(1, 2, 3, 4, 5)

numbers.filter { it % 2 == 0 }      // [2, 4]
numbers.map { it * 2 }              // [2, 4, 6, 8, 10]
numbers.reduce { acc, num -> acc + num }  // 15

// 2. 回调函数
class Button {
    var onClick: (() -> Unit)? = null
    
    fun click() {
        onClick?.invoke()
    }
}

val button = Button()
button.onClick = {
    println("Button clicked!")
}

// 3. 协程
lifecycleScope.launch {
    val result = withContext(Dispatchers.IO) {
        // Lambda 中的代码在 IO 线程执行
        api.loadData()
    }
    // 回到主线程
    updateUI(result)
}

// 4. 作用域函数
val person = Person().apply {
    name = "张三"
    age = 25
}

person.let {
    println("Name: ${it.name}")
}

person.run {
    println("Age: $age")
}

2. Lambda 与匿名函数 ​

2.1 Lambda 表达式 ​

kotlin
// Lambda 表达式
val sum = { a: Int, b: Int -> a + b }

// 简洁,但不能指定返回类型
// 返回值由最后一行推断

// 不能从 Lambda 中非局部返回(除非 inline)
fun example() {
    listOf(1, 2, 3).forEach {
        if (it == 2) {
            // return  // ❌ 错误:不能从 Lambda 返回
            return@forEach  // ✅ 正确:从 Lambda 返回
        }
    }
}

2.2 匿名函数 ​

kotlin
// 匿名函数语法
val sum = fun(a: Int, b: Int): Int {
    return a + b
}

// 可以指定返回类型
val divide = fun(a: Int, b: Int): Double {
    return a.toDouble() / b
}

// 匿名函数可以非局部返回
fun example() {
    listOf(1, 2, 3).forEach(fun(value) {
        if (value == 2) {
            return  // ✅ 正确:从匿名函数返回,不是从 example 返回
        }
        println(value)
    })
}

// 带接收者的匿名函数
val block: StringBuilder.() -> Unit = fun() {
    this.append("Hello")  // this 是 StringBuilder
    append(" World")      // this 可以省略
}

2.3 Lambda vs 匿名函数对比 ​

kotlin
// Lambda 表达式
val lambda = { x: Int -> x * 2 }

// 匿名函数
val anonymous = fun(x: Int): Int { return x * 2 }

// 对比:
// 1. Lambda 更简洁,匿名函数更明确
// 2. Lambda 返回类型由推断,匿名函数可以显式指定
// 3. Lambda 在 inline 函数中可以非局部返回
// 4. 匿名函数的 return 只从匿名函数本身返回

// 使用场景:
// - 优先使用 Lambda(简洁)
// - 需要显式返回类型时使用匿名函数
// - 需要明确 return 行为时使用匿名函数

2.4 带接收者的函数类型 ​

kotlin
// Lambda 形式
val block1: StringBuilder.() -> Unit = {
    append("Hello")  // this 是 StringBuilder
}

// 匿名函数形式
val block2: StringBuilder.() -> Unit = fun() {
    this.append("Hello")
}

// 使用
val sb = StringBuilder()
sb.block1()
sb.block2()

// 实际应用:DSL 构建器
class Dialog {
    var title: String = ""
    var message: String = ""
}

fun dialog(configure: Dialog.() -> Unit): Dialog {
    return Dialog().apply(configure)
}

// 使用
dialog {
    title = "提示"
    message = "确定吗?"
}

2.5 函数引用 ​

kotlin
// 函数引用是 Lambda 的另一种形式
fun add(a: Int, b: Int): Int = a + b

val sum = ::add  // 函数引用

// 调用
val result = sum(3, 4)  // 7

// 方法引用
class Calculator {
    fun add(a: Int, b: Int): Int = a + b
}

val calc = Calculator()
val sum2 = calc::add

// 构造函数引用
val createList = ::ArrayList
val list = createList<Int>()

// 属性引用
class User(val name: String)
val user = User("张三")
val getName = User::name
val nameValue = getName.get(user)  // "张三"

3. 接收者的 Lambda ​

3.1 带接收者的函数类型 ​

kotlin
// 语法:接收者类型。(参数) -> 返回类型
val block: StringBuilder.() -> Unit = {
    append("Hello")  // this 是 StringBuilder
    append(" ")
    append("World")
}

// 使用
val sb = StringBuilder()
sb.block()  // 在 StringBuilder 的上下文中执行
println(sb.toString())  // "Hello World"

// 显式使用 this
val block2: StringBuilder.() -> Unit = {
    this.append("Hello")  // 显式 this
}

3.2 标准库中的接收者 Lambda ​

kotlin
// let - 接收者是 it
val result = "Kotlin".let {
    it.uppercase()  // it 是 String
}

// run - 接收者是 this
val result2 = "Kotlin".run {
    this.uppercase()  // this 是 String
    length            // 返回最后一行
}

// with - 接收者是 this(不是扩展函数)
val result3 = with(StringBuilder()) {
    append("Hello")
    append(" World")
    toString()
}

// apply - 接收者是 this,返回 this
val sb = StringBuilder().apply {
    append("Hello")
    append(" World")
}  // sb 是 StringBuilder

// also - 接收者是 it,返回 this
val sb2 = StringBuilder().also {
    it.append("Hello")
}  // sb2 是 StringBuilder

3.3 创建 DSL ​

kotlin
// HTML 构建器 DSL
interface Element {
    fun render(): String
}

class Tag(val name: String, val children: MutableList<Element> = mutableListOf()) : Element {
    override fun render(): String {
        return "<$name>${children.joinToString("") { it.render() }}</$name>"
    }
}

class Text(val text: String) : Element {
    override fun render(): String = text
}

fun tag(name: String, init: Tag.() -> Unit = {}): Tag {
    val tag = Tag(name)
    tag.init()
    return tag
}

fun text(text: String): Text = Text(text)

fun Tag.child(element: Element) {
    children.add(element)
}

// 使用
val html = tag("html") {
    child(tag("body") {
        child(tag("h1") {
            child(text("Hello DSL"))
        })
        child(tag("p") {
            child(text("This is a DSL example"))
        })
    })
}

println(html.render())
// <html><body><h1>Hello DSL</h1><p>This is a DSL example</p></body></html>

3.4 类型安全的构建器 ​

kotlin
// 配置 DSL
class DatabaseConfig {
    var host: String = "localhost"
    var port: Int = 5432
    var username: String = ""
    var password: String = ""
    var database: String = ""
    
    fun validate() {
        require(username.isNotEmpty()) { "Username is required" }
        require(password.isNotEmpty()) { "Password is required" }
        require(database.isNotEmpty()) { "Database is required" }
    }
}

fun database(init: DatabaseConfig.() -> Unit): DatabaseConfig {
    val config = DatabaseConfig()
    config.init()
    config.validate()
    return config
}

// 使用
val dbConfig = database {
    host = "192.168.1.100"
    port = 5432
    username = "admin"
    password = "secret"
    database = "mydb"
}

// 嵌套 DSL
class Server {
    var host: String = ""
    var port: Int = 0
    val endpoints = mutableListOf<String>()
    
    fun endpoint(path: String, init: EndpointConfig.() -> Unit) {
        val config = EndpointConfig(path)
        config.init()
        endpoints.add(config.path)
    }
}

class EndpointConfig(val path: String) {
    var method: String = "GET"
    var timeout: Long = 5000
}

fun server(init: Server.() -> Unit): Server {
    val server = Server()
    server.init()
    return server
}

// 使用
val serverConfig = server {
    host = "localhost"
    port = 8080
    endpoint("/api/users") {
        method = "GET"
        timeout = 3000
    }
    endpoint("/api/posts") {
        method = "POST"
    }
}

3.5 作用域函数对比 ​

kotlin
val person = Person("张三", 25)

// let - 对象为 it,返回 Lambda 结果
val nameLength = person.let {
    it.name.length  // 返回 Int
}

// run - 对象为 this,返回 Lambda 结果
val nameLength2 = person.run {
    name.length  // 返回 Int
}

// with - 对象为 this,返回 Lambda 结果(不是扩展函数)
val nameLength3 = with(person) {
    name.length  // 返回 Int
}

// apply - 对象为 this,返回对象本身
val person2 = Person("李四", 30).apply {
    age = 31  // 修改属性
}  // 返回 Person

// also - 对象为 it,返回对象本身
val person3 = Person("王五", 35).also {
    println("Created: ${it.name}")  // 副作用
}  // 返回 Person

4. Lambda 捕获 ​

4.1 捕获外部变量 ​

kotlin
// Lambda 可以捕获外部变量
fun createCounter(): () -> Int {
    var count = 0  // 被捕获的变量
    return {
        count++
        count
    }
}

// 使用
val counter = createCounter()
println(counter())  // 1
println(counter())  // 2
println(counter())  // 3

// 捕获的变量是闭包的一部分
// 即使外部函数返回,变量仍然存在

4.2 捕获 this ​

kotlin
// 捕获外部类的 this
class Outer {
    private val value = "Outer"
    
    fun getPrinter(): () -> Unit {
        return {
            println(value)  // 捕获 Outer 的 value
        }
    }
}

// 内层类的 this 捕获
class Outer2 {
    val value = "Outer"
    
    inner class Inner {
        val value = "Inner"
        
        fun print() {
            val block: () -> Unit = {
                println(value)           // Inner.value(最近的 this)
                println(this@Inner.value) // 明确指定 Inner 的 this
                println(this@Outer2.value) // 明确指定 Outer2 的 this
            }
            block()
        }
    }
}

4.3 捕获可变变量 ​

kotlin
// 捕获的可变变量必须是 effectively final(Java 8+)
// Kotlin 中可以直接捕获 var

var count = 0
val increment = {
    count++  // 可以修改捕获的 var
}

increment()
println(count)  // 1

// 注意:多个 Lambda 捕获同一个 var
var shared = 0
val inc = { shared++ }
val dec = { shared-- }

inc()
inc()
dec()
println(shared)  // 1

4.4 捕获的性能考虑 ​

kotlin
// 捕获变量会创建闭包对象
// 每次捕获都会增加内存开销

// ❌ 避免:在循环中创建捕获 Lambda
fun badExample() {
    val results = mutableListOf<() -> Int>()
    for (i in 1..10) {
        results.add { i }  // 每个 Lambda 都捕获 i
    }
}

// ✅ 推荐:避免不必要的捕获
fun goodExample() {
    val results = mutableListOf<Int>()
    for (i in 1..10) {
        results.add(i)  // 直接存储值
    }
}

// 捕获 this 的开销
class MyClass {
    private val data = LargeObject()
    
    fun getPrinter(): () -> Unit {
        return {
            println(data)  // 捕获 this,持有 data 引用
        }
    }
}

// 可能导致内存泄漏
// 如果 Lambda 的生命周期比 MyClass 长

4.5 捕获与内存泄漏 ​

kotlin
// Android 中的内存泄漏示例
class MyActivity : AppCompatActivity() {
    private var callback: (() -> Unit)? = null
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        // ❌ 错误:Lambda 捕获 this(Activity)
        callback = {
            // 使用 Activity 的成员
            findViewById<View>(R.id.view)
        }
        
        // 如果 callback 的生命周期比 Activity 长
        // 会导致 Activity 无法被 GC
    }
    
    override fun onDestroy() {
        super.onDestroy()
        callback = null  // 释放引用
    }
}

// ✅ 正确做法
class MyActivity2 : AppCompatActivity() {
    private var callback: (() -> Unit)? = null
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        // 使用 WeakReference
        val weakRef = WeakReference(this)
        callback = {
            weakRef.get()?.findViewById<View>(R.id.view)
        }
    }
    
    override fun onDestroy() {
        super.onDestroy()
        callback = null
    }
}

// ✅ 使用 Lifecycle 感知
class MyActivity3 : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        lifecycleScope.launch {
            // 协程自动感知生命周期
            // Activity 销毁时自动取消
            delay(1000)
            // 安全使用 Activity
        }
    }
}

4.6 捕获最佳实践 ​

kotlin
// 1. 最小化捕获
class DataProcessor {
    private val config = Config()
    
    // ❌ 捕获整个 this
    val process: (String) -> String = { data ->
        config.process(data)
    }
    
    // ✅ 只捕获需要的
    val process2: (String) -> String = { data ->
        config.process(data)
    }
}

// 2. 避免循环引用
class MyClass {
    var callback: (() -> Unit)? = null
    
    fun setup() {
        // ❌ 循环引用:this 持有 callback,callback 捕获 this
        callback = {
            doSomething()
        }
    }
    
    // ✅ 使用 WeakReference
    fun setup2() {
        val weakRef = WeakReference(this)
        callback = {
            weakRef.get()?.doSomething()
        }
    }
}

// 3. 及时清理
class MyViewModel : ViewModel() {
    private var listener: ((String) -> Unit)? = null
    
    fun setListener(listener: (String) -> Unit) {
        this.listener = listener
    }
    
    override fun onCleared() {
        super.onCleared()
        listener = null  // 清理回调
    }
}

5. Lambda 性能 ​

5.1 Lambda 的对象创建 ​

kotlin
// Lambda 会创建函数对象
// 每次调用都会创建新对象(除非内联)

// 普通 Lambda
fun example() {
    val list = listOf(1, 2, 3)
    list.forEach { println(it) }
    // 1. 创建 Lambda 对象
    // 2. 调用 forEach 方法
    // 3. 在循环中调用 Lambda
}

// 内联 Lambda
inline fun <T> List<T>.forEach(action: (T) -> Unit) {
    for (element in this) action(element)
}

// 内联后直接展开
for (element in this) {
    println(element)  // 没有 Lambda 对象创建
}

5.2 内联优化 ​

kotlin
// inline 关键字消除 Lambda 开销
inline fun <T, R> List<T>.map(transform: (T) -> R): List<R> {
    val result = ArrayList<R>(size)
    for (item in this) {
        result.add(transform(item))  // 内联展开
    }
    return result
}

// 使用
val result = listOf(1, 2, 3).map {
    it * 2  // 直接展开为 result.add(item * 2)
}

// noinline:禁止特定 Lambda 内联
inline fun test(
    inlineParam: () -> Unit,
    noinline noInlineParam: () -> Unit
) {
    inlineParam()  // 内联
    executeLater(noInlineParam)  // 不内联,可以作为对象传递
}

fun executeLater(action: () -> Unit) {
    // 延迟执行
    action()
}

5.3 装箱开销 ​

kotlin
// 基本类型的 Lambda 参数会装箱
val list = listOf(1, 2, 3)  // List<Int>,Int 装箱为 Integer

list.forEach {
    println(it)  // it 是 Integer(装箱)
}

// 使用原始类型数组避免装箱
val array = intArrayOf(1, 2, 3)  // IntArray

array.forEach {
    println(it)  // it 是 int(原始类型)
}

// 自定义内联函数避免装箱
inline fun IntArray.forEach(action: (Int) -> Unit) {
    for (i in this.indices) {
        action(this[i])  // 没有装箱
    }
}

5.4 性能对比 ​

kotlin
// 性能测试
fun performanceTest() {
    val list = (1..10000).toList()
    
    // 1. 普通 for 循环(最快)
    var sum1 = 0
    for (item in list) {
        sum1 += item
    }
    
    // 2. 内联 forEach(接近 for 循环)
    var sum2 = 0
    list.forEach {
        sum2 += it
    }
    
    // 3. 非内联 map + sum(较慢)
    val sum3 = list.map { it * 2 }.sum()
    
    // 4. 序列(惰性求值,适合大数据)
    val sum4 = list.asSequence()
        .filter { it % 2 == 0 }
        .map { it * 2 }
        .sum()
}

// 建议:
// - 简单遍历使用 for 循环或内联 forEach
// - 复杂链式操作使用序列(Sequence)
// - 避免在循环中创建对象

5.5 序列优化 ​

kotlin
// 序列:惰性求值,避免中间集合
val list = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

// List:立即求值,创建中间集合
val result1 = list
    .filter {
        println("Filter: $it")
        it % 2 == 0
    }
    .map {
        println("Map: $it")
        it * 2
    }
    .take(2)
// 所有元素都经过 filter 和 map,即使只取 2 个

// Sequence:惰性求值,不创建中间集合
val result2 = list.asSequence()
    .filter {
        println("Filter: $it")
        it % 2 == 0
    }
    .map {
        println("Map: $it")
        it * 2
    }
    .take(2)
    .toList()
// 只处理需要的元素

// 使用场景:
// - 大数据集使用 Sequence
// - 短链式操作使用 List
// - 需要多次遍历使用 List

5.6 性能最佳实践 ​

kotlin
// 1. 使用内联函数
inline fun <T> List<T>.forEach(action: (T) -> Unit)

// 2. 避免在循环中创建 Lambda
// ❌ 不好
for (i in 1..100) {
    list.filter { it == i }  // 每次创建 Lambda
}

// ✅ 好
val filters = (1..100).map { i ->
    list.filter { it == i }
}

// 3. 使用序列处理大数据
largeList.asSequence()
    .filter { it > 0 }
    .map { it * 2 }
    .take(10)
    .toList()

// 4. 避免不必要的装箱
val array = intArrayOf(1, 2, 3)
array.forEach { println(it) }  // 没有装箱

// 5. 使用合适的集合操作
// ❌ 不好:创建中间集合
val result = list.filter { it > 0 }.map { it * 2 }

// ✅ 好:单次遍历
val result = list.mapNotNull {
    if (it > 0) it * 2 else null
}

6. 面试考点汇总 ​

6.1 基础问题 ​

Q1: Lambda 表达式的语法是什么?

kotlin
// 答案要点:
// 1. { 参数 -> 函数体 }
// 2. 单个参数可以用 it
// 3. 类型可以推断
// 4. 最后一行是返回值

// 完整语法
val sum = { a: Int, b: Int -> a + b }

// 类型推断
val sum: (Int, Int) -> Int = { a, b -> a + b }

// 单个参数
val double: (Int) -> Int = { it * 2 }

// 多行 Lambda
val complex = { x: Int ->
    val result = x * 2
    result + 1  // 返回值
}

Q2: Lambda 和匿名函数的区别?

kotlin
// 答案要点:
// 1. Lambda 更简洁,匿名函数更明确
// 2. Lambda 返回类型由推断,匿名函数可以显式指定
// 3. Lambda 在 inline 函数中可以非局部返回
// 4. 匿名函数的 return 只从匿名函数本身返回

// Lambda
val lambda = { x: Int -> x * 2 }

// 匿名函数
val anonymous = fun(x: Int): Int { return x * 2 }

Q3: 什么是尾随 Lambda?

kotlin
// 答案要点:
// 1. 最后一个参数是函数时可以放在括号外
// 2. 如果只有 Lambda 参数,括号可以省略
// 3. 提高代码可读性

// 尾随 Lambda
list.map { it * 2 }

// 只有 Lambda 参数
run {
    println("Hello")
}

// 多个参数
list.fold(0) { acc, num ->
    acc + num
}

6.2 进阶问题 ​

Q4: Lambda 如何捕获外部变量?

kotlin
// 答案要点:
// 1. Lambda 可以捕获外部作用域的变量
// 2. 捕获的变量形成闭包
// 3. 可以捕获 var 并修改
// 4. 注意内存泄漏风险

// 捕获示例
fun createCounter(): () -> Int {
    var count = 0
    return {
        count++
        count
    }
}

val counter = createCounter()
println(counter())  // 1, 2, 3...

Q5: 带接收者的 Lambda 如何使用?

kotlin
// 答案要点:
// 1. 函数类型:Receiver.(Params) -> Return
// 2. Lambda 内 this 指向接收者
// 3. 用于 DSL 和作用域函数
// 4. 标准库:let、run、with、apply、also

// 定义
val block: StringBuilder.() -> Unit = {
    append("Hello")  // this 是 StringBuilder
}

// 使用
val sb = StringBuilder()
sb.block()

// 作用域函数
person.let { it.name }
person.run { name }

Q6: inline 关键字的作用?

kotlin
// 答案要点:
// 1. 将 Lambda 代码内联到调用处
// 2. 避免 Lambda 对象创建开销
// 3. 支持非局部返回
// 4. 需要 reified 时使用

inline fun <T> List<T>.forEach(action: (T) -> Unit) {
    for (element in this) action(element)
}

// 内联后直接展开
for (element in this) {
    println(element)
}

6.3 原理问题 ​

Q7: Lambda 的性能开销?

kotlin
// 答案要点:
// 1. Lambda 会创建函数对象
// 2. 有分配和 GC 开销
// 3. 使用 inline 可以消除开销
// 4. 基本类型参数注意装箱

// 普通 Lambda
list.forEach { println(it) }
// 1. 创建 Lambda 对象
// 2. 调用 forEach
// 3. 调用 Lambda

// 内联 Lambda
inline fun <T> List<T>.forEach(action: (T) -> Unit)
// 直接展开,无对象创建

Q8: 闭包的实现原理?

kotlin
// 答案要点:
// 1. Lambda 捕获外部变量形成闭包
// 2. 捕获的变量存储在 Lambda 对象中
// 3. 即使外部函数返回,变量仍然存在
// 4. 可变变量需要特殊处理

// 闭包示例
fun createCounter(): () -> Int {
    var count = 0  // 被捕获
    return { count++ }
}
// count 存储在 Lambda 对象中
// 即使 createCounter 返回,count 仍然存在

6.4 实战问题 ​

Q9: 如何避免 Lambda 导致的内存泄漏?

kotlin
// 答案要点:
// 1. 注意 Lambda 捕获 this
// 2. 使用 WeakReference
// 3. 及时清理回调引用
// 4. 使用 Lifecycle 感知组件

// Android 示例
class MyActivity : AppCompatActivity() {
    private var callback: (() -> Unit)? = null
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        // 使用 WeakReference
        val weakRef = WeakReference(this)
        callback = {
            weakRef.get()?.findViewById<View>(R.id.view)
        }
    }
    
    override fun onDestroy() {
        super.onDestroy()
        callback = null  // 清理
    }
}

Q10: 如何使用 Lambda 创建 DSL?

kotlin
// 答案要点:
// 1. 使用带接收者的 Lambda
// 2. 使用 apply/scope 函数
// 3. 提供清晰的配置 API
// 4. 返回构建的对象

// DSL 示例
class Dialog {
    var title: String = ""
    var message: String = ""
}

fun dialog(configure: Dialog.() -> Unit): Dialog {
    return Dialog().apply(configure)
}

// 使用
dialog {
    title = "提示"
    message = "确定吗?"
}

Q11: 标准库中有哪些作用域函数?

kotlin
// 答案要点:
// 1. let - 对象为 it,返回 Lambda 结果
// 2. run - 对象为 this,返回 Lambda 结果
// 3. with - 对象为 this,返回 Lambda 结果(非扩展)
// 4. apply - 对象为 this,返回对象本身
// 5. also - 对象为 it,返回对象本身

val person = Person("张三", 25)

person.let { it.name }           // it 是 Person
person.run { name }              // this 是 Person
with(person) { name }            // this 是 Person
person.apply { age = 26 }        // 返回 Person
person.also { println(it) }      // 返回 Person

最佳实践总结 ​

✅ 推荐做法 ​

kotlin
// 1. 使用简洁的 Lambda 语法
list.map { it * 2 }

// 2. 使用尾随 Lambda
list.fold(0) { acc, num ->
    acc + num
}

// 3. 使用内联函数
inline fun <T> List<T>.forEach(action: (T) -> Unit)

// 4. 清晰命名 Lambda 参数
list.map { number -> number * 2 }

// 5. 使用作用域函数
person.let { println(it.name) }

❌ 避免做法 ​

kotlin
// 1. 避免过长的 Lambda
list.map {
    // 几十行代码
}

// 2. 避免嵌套过深
list.map { x ->
    list2.map { y ->
        list3.map { z ->
            // ...
        }
    }
}

// 3. 避免内存泄漏
// Lambda 捕获 this 时要注意生命周期

// 4. 避免不必要的装箱
// 使用原始类型数组

参考资料 ​


最后更新:2026-04-14