在 Kotlin 中,Lambda 是非常重要的语法。它可以让代码更加简洁,尤其是在 Android 开发中,点击事件、集合操作、回调封装、高阶函数、协程、Jetpack Compose 中都会大量使用 Lambda。

简单理解:

Lambda 就是一段可以作为值传递的代码。

也可以理解为:

Lambda 是一种匿名函数。

普通函数写法:

fun sayHello() {
    println("Hello Kotlin")
}

Lambda 写法:

val sayHello = {
    println("Hello Kotlin")
}

sayHello()

一、什么是 Lambda?

Lambda 表达式是一段没有函数名的代码块。

基本格式:

{ 参数列表 ->
    函数体
}

示例:

val add = { a: Int, b: Int ->
    a + b
}

val result = add(10, 20)
println(result)

输出结果:

30

这个 Lambda 的含义是:接收两个 Int 参数 ab,返回 a + b 的结果。


二、Lambda 的基本写法

1. 无参数 Lambda

val action = {
    println("执行任务")
}

action()

输出结果:

执行任务

这里的 action 可以理解为一个变量,只不过它保存的是一段代码逻辑。


2. 有参数 Lambda

val greet = { name: String ->
    println("你好,$name")
}

greet("张三")

输出结果:

你好,张三

3. 有多个参数 Lambda

val add = { a: Int, b: Int ->
    a + b
}

val result = add(10, 20)
println(result)

输出结果:

30

4. Lambda 的最后一行就是返回值

Lambda 中不需要写 return

val add = { a: Int, b: Int ->
    a + b
}

这里 a + b 就是 Lambda 的返回值。

再看一个例子:

val getName = {
    "张三"
}

val name = getName()
println(name)

输出结果:

张三

三、Lambda 的函数类型

Lambda 本质上是函数类型。

val action: () -> Unit = {
    println("执行任务")
}

这里的 () -> Unit 表示:没有参数,没有返回值的函数类型。

常见函数类型如下:

函数类型含义
() -> Unit无参数、无返回值
(String) -> Unit一个 String 参数、无返回值
(Int, Int) -> Int两个 Int 参数、返回 Int
() -> String无参数、返回 String

1. 无参数无返回值

val action: () -> Unit = {
    println("Hello Kotlin")
}

action()

2. 有参数无返回值

val printName: (String) -> Unit = { name ->
    println(name)
}

printName("张三")

3. 有参数有返回值

val add: (Int, Int) -> Int = { a, b ->
    a + b
}

val result = add(10, 20)
println(result)

4. 无参数有返回值

val getUserName: () -> String = {
    "张三"
}

val name = getUserName()
println(name)

四、Lambda 和普通函数的区别

普通函数:

fun add(a: Int, b: Int): Int {
    return a + b
}

Lambda 写法:

val add = { a: Int, b: Int ->
    a + b
}

区别如下:

对比项普通函数Lambda
是否有函数名通常没有
是否可以赋值给变量一般不直接赋值可以
是否可以作为参数传递可以通过函数引用传递可以直接传递
常见用途定义明确功能回调、集合操作、高阶函数
写法更正式更简洁

五、Lambda 作为函数参数

Lambda 最常见的使用方式,就是作为函数参数传递。

fun doSomething(action: () -> Unit) {
    println("开始执行")
    action()
    println("执行结束")
}

调用:

doSomething {
    println("正在执行任务")
}

输出结果:

开始执行
正在执行任务
执行结束

这里的 action: () -> Unit 表示 doSomething 接收一段没有参数、没有返回值的代码。


六、带参数的 Lambda 作为函数参数

fun calculate(a: Int, b: Int, operation: (Int, Int) -> Int): Int {
    return operation(a, b)
}

调用加法:

val result = calculate(10, 20) { x, y ->
    x + y
}

println(result)

输出结果:

30

调用乘法:

val result = calculate(10, 20) { x, y ->
    x * y
}

println(result)

输出结果:

200

这里的 operation: (Int, Int) -> Int 表示:operation 是一个函数参数,它接收两个 Int,返回一个 Int

calculate 本身不关心具体怎么算,具体计算规则由调用方通过 Lambda 传入。


七、尾随 Lambda

如果函数的最后一个参数是 Lambda,那么调用时可以把 Lambda 写到小括号外面。

fun doSomething(action: () -> Unit) {
    action()
}

普通写法:

doSomething({
    println("执行任务")
})

Kotlin 推荐写法:

doSomething {
    println("执行任务")
}

这种写法叫尾随 Lambda

Android 点击事件就是典型例子:

button.setOnClickListener {
    println("按钮被点击")
}

八、如果 Lambda 是唯一参数,可以省略小括号

如果一个函数只有一个 Lambda 参数,那么调用时可以省略 ()

fun execute(action: () -> Unit) {
    action()
}

推荐写法:

execute {
    println("执行任务")
}

不推荐写成:

execute({
    println("执行任务")
})

九、it 默认参数名

如果 Lambda 只有一个参数,Kotlin 会自动提供默认参数名 it

val names = listOf("张三", "李四", "王五")

names.forEach { name ->
    println(name)
}

可以简写成:

names.forEach {
    println(it)
}

这里的 it 表示当前遍历到的元素。

再看一个例子:

val numbers = listOf(1, 2, 3, 4, 5)

val result = numbers.filter {
    it > 3
}

println(result)

输出结果:

[4, 5]

十、Lambda 中多个参数不能使用 it

如果 Lambda 有多个参数,就不能使用默认的 it,需要自己命名。

val add = { a: Int, b: Int ->
    a + b
}

或者:

val result = calculate(10, 20) { x, y ->
    x + y
}

这里必须写 x, y ->,不能写 it


十一、Lambda 中不需要 return

Lambda 默认返回最后一行表达式。

正确写法:

val add = { a: Int, b: Int ->
    a + b
}

不推荐在普通 Lambda 中直接写:

val add = { a: Int, b: Int ->
    return a + b // 错误或不适合普通 Lambda
}

如果需要提前结束逻辑,可以使用普通函数,或者在特定场景使用标签返回。


十二、Lambda 中的标签返回

在某些场景下,比如 forEach 中,不能直接使用普通 return,否则可能会影响外层函数。

fun test() {
    val numbers = listOf(1, 2, 3, 4, 5)

    numbers.forEach {
        if (it == 3) {
            return
        }

        println(it)
    }

    println("循环结束")
}

这里的 return 会直接结束 test() 函数。

如果只是想跳过当前 Lambda,可以使用标签返回:

fun test() {
    val numbers = listOf(1, 2, 3, 4, 5)

    numbers.forEach {
        if (it == 3) {
            return@forEach
        }

        println(it)
    }

    println("循环结束")
}

输出结果:

1
2
4
5
循环结束

return@forEach 表示只结束当前这一次 forEach 的 Lambda,不结束整个 test() 函数。


十三、Android 点击事件中的 Lambda

传统匿名对象写法:

button.setOnClickListener(object : View.OnClickListener {
    override fun onClick(v: View?) {
        Toast.makeText(this@MainActivity, "按钮被点击", Toast.LENGTH_SHORT).show()
    }
})

Kotlin Lambda 写法:

button.setOnClickListener {
    Toast.makeText(this, "按钮被点击", Toast.LENGTH_SHORT).show()
}

Lambda 写法明显更简洁。


十四、多个按钮点击事件

loginButton.setOnClickListener {
    login()
}

registerButton.setOnClickListener {
    register()
}

cancelButton.setOnClickListener {
    finish()
}

对应函数:

fun login() {
    println("登录")
}

fun register() {
    println("注册")
}

如果多个按钮逻辑类似,也可以封装扩展函数:

fun View.onClick(action: () -> Unit) {
    setOnClickListener {
        action()
    }
}

使用:

loginButton.onClick {
    login()
}

registerButton.onClick {
    register()
}

十五、Lambda 和集合操作

Kotlin 集合中大量使用 Lambda。

1. forEach 遍历集合

val names = listOf("张三", "李四", "王五")

names.forEach {
    println(it)
}

输出结果:

张三
李四
王五

2. filter 筛选数据

val numbers = listOf(1, 2, 3, 4, 5)

val result = numbers.filter {
    it > 3
}

println(result)

输出结果:

[4, 5]

3. map 转换数据

val numbers = listOf(1, 2, 3)

val result = numbers.map {
    it * 2
}

println(result)

输出结果:

[2, 4, 6]

4. find 查找数据

val names = listOf("Kotlin", "Java", "Android")

val result = names.find {
    it == "Android"
}

println(result)

输出结果:

Android

如果没有找到,返回 null


5. any 判断是否存在

val names = listOf("Kotlin", "Java", "Android")

val hasAndroid = names.any {
    it == "Android"
}

println(hasAndroid)

输出结果:

true

6. all 判断是否全部满足

val numbers = listOf(2, 4, 6)

val result = numbers.all {
    it % 2 == 0
}

println(result)

输出结果:

true

7. count 统计数量

val numbers = listOf(1, 2, 3, 4, 5)

val count = numbers.count {
    it > 3
}

println(count)

输出结果:

2

十六、Android 中常见集合处理示例

1. 筛选有效用户名

val names = listOf("Kotlin", "", "Android", " ", "Jetpack")

val validNames = names.filter {
    it.isNotBlank()
}

println(validNames)

输出结果:

[Kotlin, Android, Jetpack]

2. 获取用户名称列表

data class User(
    val id: Int,
    val name: String,
    val age: Int
)
val userList = listOf(
    User(1, "张三", 18),
    User(2, "李四", 20),
    User(3, "王五", 22)
)

val nameList = userList.map {
    it.name
}

println(nameList)

输出结果:

[张三, 李四, 王五]

3. 筛选成年人

val adults = userList.filter {
    it.age >= 18
}

4. 查找指定用户

val user = userList.find {
    it.id == 2
}

println(user)

输出结果:

User(id=2, name=李四, age=20)

5. 判断是否存在未成年人

val hasChild = userList.any {
    it.age < 18
}

println(hasChild)

十七、Lambda 和高阶函数

如果一个函数接收 Lambda 作为参数,或者返回 Lambda,那么这个函数就是高阶函数。

示例:

fun repeatTask(times: Int, task: () -> Unit) {
    for (i in 1..times) {
        task()
    }
}

调用:

repeatTask(3) {
    println("执行任务")
}

输出结果:

执行任务
执行任务
执行任务

这个例子中 task: () -> Unit 就是 Lambda 类型参数。


十八、自定义高阶函数

1. 封装执行流程

fun runTask(task: () -> Unit) {
    println("任务开始")
    task()
    println("任务结束")
}

使用:

runTask {
    println("正在下载文件")
}

输出结果:

任务开始
正在下载文件
任务结束

2. 封装登录逻辑

fun login(
    username: String,
    password: String,
    onSuccess: () -> Unit,
    onFailed: (String) -> Unit
) {
    if (username.isBlank()) {
        onFailed("用户名不能为空")
        return
    }

    if (password.isBlank()) {
        onFailed("密码不能为空")
        return
    }

    if (username == "admin" && password == "123456") {
        onSuccess()
    } else {
        onFailed("用户名或密码错误")
    }
}

调用:

login(
    username = "admin",
    password = "123456",
    onSuccess = {
        println("登录成功")
    },
    onFailed = { message ->
        println("登录失败:$message")
    }
)

输出结果:

登录成功

十九、Lambda 和接口回调的关系

在 Android 中,很多接口回调可以用 Lambda 简化。

传统接口写法:

interface LoginCallback {
    fun onSuccess()
    fun onFailed(message: String)
}

使用接口:

loginManager.login("admin", "123456", object : LoginCallback {
    override fun onSuccess() {
        println("登录成功")
    }

    override fun onFailed(message: String) {
        println("登录失败:$message")
    }
})

如果改成 Lambda 参数:

fun login(
    username: String,
    password: String,
    onSuccess: () -> Unit,
    onFailed: (String) -> Unit
) {
    // 登录逻辑
}

调用就可以变成:

login(
    username = "admin",
    password = "123456",
    onSuccess = {
        println("登录成功")
    },
    onFailed = {
        println("登录失败:$it")
    }
)

Lambda 可以减少很多模板代码。


二十、fun interface 函数式接口

Kotlin 中支持 fun interface,也叫函数式接口。

它的特点是:只能有一个抽象方法

定义:

fun interface OnItemClickListener {
    fun onItemClick(position: Int)
}

使用匿名对象:

val listener = object : OnItemClickListener {
    override fun onItemClick(position: Int) {
        println("点击了第 $position 项")
    }
}

可以简写成 Lambda:

val listener = OnItemClickListener { position ->
    println("点击了第 $position 项")
}

这种写法适合只有一个回调方法的接口。


二十一、Lambda 和扩展函数结合

Kotlin 中经常把 Lambda 和扩展函数结合使用。

例如封装 View 点击事件:

fun View.onClick(action: () -> Unit) {
    setOnClickListener {
        action()
    }
}

使用:

button.onClick {
    Toast.makeText(this, "按钮被点击", Toast.LENGTH_SHORT).show()
}

防止重复点击:

fun View.onSingleClick(interval: Long = 500, action: () -> Unit) {
    var lastClickTime = 0L

    setOnClickListener {
        val currentTime = System.currentTimeMillis()

        if (currentTime - lastClickTime > interval) {
            lastClickTime = currentTime
            action()
        }
    }
}

使用:

button.onSingleClick {
    println("执行点击逻辑")
}

二十二、Lambda 和作用域函数

Kotlin 中常见的作用域函数也大量使用 Lambda。

常见作用域函数:

let
run
with
apply
also

1. let

let 常用于非空判断后执行逻辑。

val name: String? = "张三"

name?.let {
    println("姓名:$it")
}

Android 中常见写法:

user?.let {
    textView.text = it.name
}

2. apply

apply 常用于对象初始化。

val user = User().apply {
    name = "张三"
    age = 18
}

等价于:

val user = User()
user.name = "张三"
user.age = 18

Android 中常见写法:

val intent = Intent(this, DetailActivity::class.java).apply {
    putExtra("userId", 1001)
    putExtra("userName", "张三")
}

3. also

also 常用于附加操作,比如打印日志。

val names = mutableListOf("Kotlin", "Android").also {
    println("当前列表:$it")
}

4. run

run 常用于执行一段代码并返回最后一行结果。

val result = run {
    val a = 10
    val b = 20
    a + b
}

println(result)

输出结果:

30

5. with

with 常用于对同一个对象进行多次操作。

with(textView) {
    text = "Hello Kotlin"
    textSize = 16f
    visibility = View.VISIBLE
}

二十三、Lambda 中的 this 和 it

在 Lambda 中,经常会看到 thisit

关键字常见场景含义
itletforEachfiltermapLambda 的单个参数
thisapplyrun、带接收者 Lambda当前接收者对象

it 示例

val names = listOf("张三", "李四")

names.forEach {
    println(it)
}

这里 it 表示当前遍历到的元素。

this 示例

val user = User().apply {
    name = "张三"
    age = 18
}

等价理解:

val user = User().apply {
    this.name = "张三"
    this.age = 18
}

二十四、带接收者的 Lambda

带接收者的 Lambda 是 Kotlin 中比较高级但很常见的写法。

普通 Lambda:

val block: (String) -> Unit = {
    println(it)
}

带接收者的 Lambda:

val block: String.() -> Unit = {
    println(this)
}

区别:

类型含义
(String) -> Unit接收一个 String 参数
String.() -> UnitString 对象的上下文中执行

示例:

fun String.printSelf(block: String.() -> Unit) {
    this.block()
}

"Hello".printSelf {
    println(this)
}

输出结果:

Hello

Android 和 Compose 中会大量看到这种写法。


二十五、Android 中自定义 DSL 风格写法

带接收者 Lambda 可以写出类似 DSL 的代码。

class DialogBuilder {
    var title: String = ""
    var message: String = ""

    fun show() {
        println("标题:$title")
        println("内容:$message")
    }
}

定义函数:

fun showDialog(block: DialogBuilder.() -> Unit) {
    val builder = DialogBuilder()
    builder.block()
    builder.show()
}

使用:

showDialog {
    title = "提示"
    message = "确定要删除吗?"
}

输出结果:

标题:提示
内容:确定要删除吗?

这里的 DialogBuilder.() -> Unit 表示 Lambda 在 DialogBuilder 对象内部执行。


二十六、Lambda 在 RecyclerView 中的使用

传统 Adapter 点击事件常用接口回调,现在可以用 Lambda 简化。

data class User(
    val id: Int,
    val name: String
)

Adapter 示例:

class UserAdapter(
    private val userList: List<User>,
    private val onItemClick: (User) -> Unit
) : RecyclerView.Adapter<UserAdapter.UserViewHolder>() {

    class UserViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder {
        TODO("创建 ViewHolder")
    }

    override fun onBindViewHolder(holder: UserViewHolder, position: Int) {
        val user = userList[position]

        holder.itemView.setOnClickListener {
            onItemClick(user)
        }
    }

    override fun getItemCount(): Int {
        return userList.size
    }
}

使用:

val adapter = UserAdapter(userList) { user ->
    Toast.makeText(this, "点击了:${user.name}", Toast.LENGTH_SHORT).show()
}

这样就不需要单独定义 OnItemClickListener 接口。


二十七、Lambda 在协程中的使用

Android Kotlin 协程中也大量使用 Lambda。

lifecycleScope.launch {
    println("执行协程任务")
}

这里 {} 中的代码就是 Lambda。

withContext(Dispatchers.IO) {
    println("执行耗时任务")
}

这里 {} 也是 Lambda,表示在 IO 线程中执行的代码块。


二十八、Lambda 在 Jetpack Compose 中的使用

Jetpack Compose 中更是大量使用 Lambda。

Button(
    onClick = {
        println("按钮被点击")
    }
) {
    Text("点击我")
}

这里有两个 Lambda:

onClick = {
    println("按钮被点击")
}

表示按钮点击时执行的逻辑。

{
    Text("点击我")
}

表示 Button 内部显示的内容。

再比如:

Column {
    Text("标题")
    Text("内容")
}

Column {} 中的内容也是 Lambda。


二十九、Lambda 使用注意事项

1. Lambda 不要写得太长

不推荐:

button.setOnClickListener {
    // 大量业务逻辑
    // 网络请求
    // 数据处理
    // UI 更新
}

推荐拆成函数:

button.setOnClickListener {
    login()
}

fun login() {
    // 登录逻辑
}

2. 参数含义不清时,不要滥用 it

简单场景可以使用 it

userList.map {
    it.name
}

复杂场景建议命名参数:

userList.map { user ->
    user.name
}

3. 多层 Lambda 注意 this 指向

如果嵌套较深,thisit 容易混淆,建议显式命名参数或拆分函数。


4. 需要 break / continue 时慎用 forEach

普通 for 可以使用:

for (item in list) {
    if (item == "Android") {
        break
    }
}

forEach 里不能直接像普通循环那样使用 breakcontinue

需要中途退出时,优先使用普通 for


5. 注意内存泄漏

在 Android 中,如果 Lambda 长时间持有 ActivityView 引用,可能导致内存泄漏。

例如把 Activity 的 Lambda 保存到全局对象中,就需要谨慎。

一般点击事件、局部集合操作问题不大,但长生命周期对象中保存短生命周期对象的 Lambda,要特别注意。


三十、Lambda 使用建议

场景建议
点击事件使用 Lambda 简化
集合遍历使用 forEachmapfilter
简单回调使用 Lambda
多状态回调可以使用接口或密封类
复杂业务逻辑Lambda 中只调用函数,不堆大量代码
需要中途退出循环优先使用普通 for
单参数简单逻辑可以使用 it
复杂逻辑建议给参数命名
对象初始化使用 apply
非空处理使用 let
附加操作使用 also

三十一、完整示例:使用 Lambda 封装登录逻辑

class LoginManager {

    fun login(
        username: String,
        password: String,
        onSuccess: (String) -> Unit,
        onFailed: (String) -> Unit
    ) {
        if (username.isBlank()) {
            onFailed("用户名不能为空")
            return
        }

        if (password.isBlank()) {
            onFailed("密码不能为空")
            return
        }

        if (username == "admin" && password == "123456") {
            onSuccess(username)
        } else {
            onFailed("用户名或密码错误")
        }
    }
}

使用:

fun main() {
    val loginManager = LoginManager()

    loginManager.login(
        username = "admin",
        password = "123456",
        onSuccess = { username ->
            println("登录成功,欢迎 $username")
        },
        onFailed = { error ->
            println("登录失败:$error")
        }
    )
}

输出结果:

登录成功,欢迎 admin

这个例子中:

参数类型作用
onSuccess(String) -> Unit登录成功时执行
onFailed(String) -> Unit登录失败时执行

三十二、完整示例:集合 Lambda 综合使用

data class User(
    val id: Int,
    val name: String,
    val age: Int
)

fun main() {
    val userList = listOf(
        User(1, "张三", 18),
        User(2, "李四", 16),
        User(3, "王五", 22),
        User(4, "赵六", 15)
    )

    val adultNames = userList
        .filter { user ->
            user.age >= 18
        }
        .map { user ->
            user.name
        }

    println(adultNames)
}

输出结果:

[张三, 王五]

这个例子中:

函数作用
filter筛选成年人
mapUser 转换成用户名

三十三、总结

Lambda 是 Kotlin 中非常重要的语法。

基本格式:

{ 参数 ->
    函数体
}

常见写法:

val action = {
    println("执行任务")
}
val add = { a: Int, b: Int ->
    a + b
}

函数类型:

类型含义
() -> Unit无参数、无返回值
(String) -> Unit一个 String 参数、无返回值
(Int, Int) -> Int两个 Int 参数、返回 Int
() -> String无参数、返回 String

Android 中常见 Lambda 场景:

场景示例
点击事件button.setOnClickListener { }
集合遍历list.forEach { }
数据筛选list.filter { }
数据转换list.map { }
回调封装onSuccess: () -> Unit
扩展函数fun View.onClick(action: () -> Unit)
作用域函数letapplyalsorun
协程lifecycleScope.launch { }
ComposeButton(onClick = { }) { }

最后记住一句话:

Lambda 的作用,就是把一段代码当作参数传递,让代码更简洁、更灵活。

在 Android Kotlin 开发中,熟练掌握 Lambda 之后,你会更容易理解点击事件、集合操作、高阶函数、协程以及 Jetpack Compose 的写法。

更多推荐