在 Kotlin 中,Lambda 是非常重要的语法。它可以让代码更加简洁,尤其是在 Android 开发中,点击事件、集合操作、回调封装、高阶函数、协程、Jetpack Compose 中都会大量使用 Lambda。
简单理解:
text
Lambda 就是一段可以作为值传递的代码。
也可以理解为:
text
Lambda 是一种匿名函数。
普通函数写法:
kotlin
fun sayHello() {
println("Hello Kotlin")
}
Lambda 写法:
kotlin
val sayHello = {
println("Hello Kotlin")
}
sayHello()
一、什么是 Lambda?
Lambda 表达式是一段没有函数名的代码块。
基本格式:
kotlin
{ 参数列表 ->
函数体
}
示例:
kotlin
val add = { a: Int, b: Int ->
a + b
}
val result = add(10, 20)
println(result)
输出结果:
text
30
这个 Lambda 的含义是:接收两个 Int 参数 a 和 b,返回 a + b 的结果。
二、Lambda 的基本写法
1. 无参数 Lambda
kotlin
val action = {
println("执行任务")
}
action()
输出结果:
text
执行任务
这里的 action 可以理解为一个变量,只不过它保存的是一段代码逻辑。
2. 有参数 Lambda
kotlin
val greet = { name: String ->
println("你好,$name")
}
greet("张三")
输出结果:
text
你好,张三
3. 有多个参数 Lambda
kotlin
val add = { a: Int, b: Int ->
a + b
}
val result = add(10, 20)
println(result)
输出结果:
text
30
4. Lambda 的最后一行就是返回值
Lambda 中不需要写 return。
kotlin
val add = { a: Int, b: Int ->
a + b
}
这里 a + b 就是 Lambda 的返回值。
再看一个例子:
kotlin
val getName = {
"张三"
}
val name = getName()
println(name)
输出结果:
text
张三
三、Lambda 的函数类型
Lambda 本质上是函数类型。
kotlin
val action: () -> Unit = {
println("执行任务")
}
这里的 () -> Unit 表示:没有参数,没有返回值的函数类型。
常见函数类型如下:
| 函数类型 | 含义 |
|---|---|
() -> Unit |
无参数、无返回值 |
(String) -> Unit |
一个 String 参数、无返回值 |
(Int, Int) -> Int |
两个 Int 参数、返回 Int |
() -> String |
无参数、返回 String |
1. 无参数无返回值
kotlin
val action: () -> Unit = {
println("Hello Kotlin")
}
action()
2. 有参数无返回值
kotlin
val printName: (String) -> Unit = { name ->
println(name)
}
printName("张三")
3. 有参数有返回值
kotlin
val add: (Int, Int) -> Int = { a, b ->
a + b
}
val result = add(10, 20)
println(result)
4. 无参数有返回值
kotlin
val getUserName: () -> String = {
"张三"
}
val name = getUserName()
println(name)
四、Lambda 和普通函数的区别
普通函数:
kotlin
fun add(a: Int, b: Int): Int {
return a + b
}
Lambda 写法:
kotlin
val add = { a: Int, b: Int ->
a + b
}
区别如下:
| 对比项 | 普通函数 | Lambda |
|---|---|---|
| 是否有函数名 | 有 | 通常没有 |
| 是否可以赋值给变量 | 一般不直接赋值 | 可以 |
| 是否可以作为参数传递 | 可以通过函数引用传递 | 可以直接传递 |
| 常见用途 | 定义明确功能 | 回调、集合操作、高阶函数 |
| 写法 | 更正式 | 更简洁 |
五、Lambda 作为函数参数
Lambda 最常见的使用方式,就是作为函数参数传递。
kotlin
fun doSomething(action: () -> Unit) {
println("开始执行")
action()
println("执行结束")
}
调用:
kotlin
doSomething {
println("正在执行任务")
}
输出结果:
text
开始执行
正在执行任务
执行结束
这里的 action: () -> Unit 表示 doSomething 接收一段没有参数、没有返回值的代码。
六、带参数的 Lambda 作为函数参数
kotlin
fun calculate(a: Int, b: Int, operation: (Int, Int) -> Int): Int {
return operation(a, b)
}
调用加法:
kotlin
val result = calculate(10, 20) { x, y ->
x + y
}
println(result)
输出结果:
text
30
调用乘法:
kotlin
val result = calculate(10, 20) { x, y ->
x * y
}
println(result)
输出结果:
text
200
这里的 operation: (Int, Int) -> Int 表示:operation 是一个函数参数,它接收两个 Int,返回一个 Int。
calculate 本身不关心具体怎么算,具体计算规则由调用方通过 Lambda 传入。
七、尾随 Lambda
如果函数的最后一个参数是 Lambda,那么调用时可以把 Lambda 写到小括号外面。
kotlin
fun doSomething(action: () -> Unit) {
action()
}
普通写法:
kotlin
doSomething({
println("执行任务")
})
Kotlin 推荐写法:
kotlin
doSomething {
println("执行任务")
}
这种写法叫尾随 Lambda。
Android 点击事件就是典型例子:
kotlin
button.setOnClickListener {
println("按钮被点击")
}
八、如果 Lambda 是唯一参数,可以省略小括号
如果一个函数只有一个 Lambda 参数,那么调用时可以省略 ()。
kotlin
fun execute(action: () -> Unit) {
action()
}
推荐写法:
kotlin
execute {
println("执行任务")
}
不推荐写成:
kotlin
execute({
println("执行任务")
})
九、it 默认参数名
如果 Lambda 只有一个参数,Kotlin 会自动提供默认参数名 it。
kotlin
val names = listOf("张三", "李四", "王五")
names.forEach { name ->
println(name)
}
可以简写成:
kotlin
names.forEach {
println(it)
}
这里的 it 表示当前遍历到的元素。
再看一个例子:
kotlin
val numbers = listOf(1, 2, 3, 4, 5)
val result = numbers.filter {
it > 3
}
println(result)
输出结果:
text
[4, 5]
十、Lambda 中多个参数不能使用 it
如果 Lambda 有多个参数,就不能使用默认的 it,需要自己命名。
kotlin
val add = { a: Int, b: Int ->
a + b
}
或者:
kotlin
val result = calculate(10, 20) { x, y ->
x + y
}
这里必须写 x, y ->,不能写 it。
十一、Lambda 中不需要 return
Lambda 默认返回最后一行表达式。
正确写法:
kotlin
val add = { a: Int, b: Int ->
a + b
}
不推荐在普通 Lambda 中直接写:
kotlin
val add = { a: Int, b: Int ->
return a + b // 错误或不适合普通 Lambda
}
如果需要提前结束逻辑,可以使用普通函数,或者在特定场景使用标签返回。
十二、Lambda 中的标签返回
在某些场景下,比如 forEach 中,不能直接使用普通 return,否则可能会影响外层函数。
kotlin
fun test() {
val numbers = listOf(1, 2, 3, 4, 5)
numbers.forEach {
if (it == 3) {
return
}
println(it)
}
println("循环结束")
}
这里的 return 会直接结束 test() 函数。
如果只是想跳过当前 Lambda,可以使用标签返回:
kotlin
fun test() {
val numbers = listOf(1, 2, 3, 4, 5)
numbers.forEach {
if (it == 3) {
return@forEach
}
println(it)
}
println("循环结束")
}
输出结果:
text
1
2
4
5
循环结束
return@forEach 表示只结束当前这一次 forEach 的 Lambda,不结束整个 test() 函数。
十三、Android 点击事件中的 Lambda
传统匿名对象写法:
kotlin
button.setOnClickListener(object : View.OnClickListener {
override fun onClick(v: View?) {
Toast.makeText(this@MainActivity, "按钮被点击", Toast.LENGTH_SHORT).show()
}
})
Kotlin Lambda 写法:
kotlin
button.setOnClickListener {
Toast.makeText(this, "按钮被点击", Toast.LENGTH_SHORT).show()
}
Lambda 写法明显更简洁。
十四、多个按钮点击事件
kotlin
loginButton.setOnClickListener {
login()
}
registerButton.setOnClickListener {
register()
}
cancelButton.setOnClickListener {
finish()
}
对应函数:
kotlin
fun login() {
println("登录")
}
fun register() {
println("注册")
}
如果多个按钮逻辑类似,也可以封装扩展函数:
kotlin
fun View.onClick(action: () -> Unit) {
setOnClickListener {
action()
}
}
使用:
kotlin
loginButton.onClick {
login()
}
registerButton.onClick {
register()
}
十五、Lambda 和集合操作
Kotlin 集合中大量使用 Lambda。
1. forEach 遍历集合
kotlin
val names = listOf("张三", "李四", "王五")
names.forEach {
println(it)
}
输出结果:
text
张三
李四
王五
2. filter 筛选数据
kotlin
val numbers = listOf(1, 2, 3, 4, 5)
val result = numbers.filter {
it > 3
}
println(result)
输出结果:
text
[4, 5]
3. map 转换数据
kotlin
val numbers = listOf(1, 2, 3)
val result = numbers.map {
it * 2
}
println(result)
输出结果:
text
[2, 4, 6]
4. find 查找数据
kotlin
val names = listOf("Kotlin", "Java", "Android")
val result = names.find {
it == "Android"
}
println(result)
输出结果:
text
Android
如果没有找到,返回 null。
5. any 判断是否存在
kotlin
val names = listOf("Kotlin", "Java", "Android")
val hasAndroid = names.any {
it == "Android"
}
println(hasAndroid)
输出结果:
text
true
6. all 判断是否全部满足
kotlin
val numbers = listOf(2, 4, 6)
val result = numbers.all {
it % 2 == 0
}
println(result)
输出结果:
text
true
7. count 统计数量
kotlin
val numbers = listOf(1, 2, 3, 4, 5)
val count = numbers.count {
it > 3
}
println(count)
输出结果:
text
2
十六、Android 中常见集合处理示例
1. 筛选有效用户名
kotlin
val names = listOf("Kotlin", "", "Android", " ", "Jetpack")
val validNames = names.filter {
it.isNotBlank()
}
println(validNames)
输出结果:
text
[Kotlin, Android, Jetpack]
2. 获取用户名称列表
kotlin
data class User(
val id: Int,
val name: String,
val age: Int
)
kotlin
val userList = listOf(
User(1, "张三", 18),
User(2, "李四", 20),
User(3, "王五", 22)
)
val nameList = userList.map {
it.name
}
println(nameList)
输出结果:
text
[张三, 李四, 王五]
3. 筛选成年人
kotlin
val adults = userList.filter {
it.age >= 18
}
4. 查找指定用户
kotlin
val user = userList.find {
it.id == 2
}
println(user)
输出结果:
text
User(id=2, name=李四, age=20)
5. 判断是否存在未成年人
kotlin
val hasChild = userList.any {
it.age < 18
}
println(hasChild)
十七、Lambda 和高阶函数
如果一个函数接收 Lambda 作为参数,或者返回 Lambda,那么这个函数就是高阶函数。
示例:
kotlin
fun repeatTask(times: Int, task: () -> Unit) {
for (i in 1..times) {
task()
}
}
调用:
kotlin
repeatTask(3) {
println("执行任务")
}
输出结果:
text
执行任务
执行任务
执行任务
这个例子中 task: () -> Unit 就是 Lambda 类型参数。
十八、自定义高阶函数
1. 封装执行流程
kotlin
fun runTask(task: () -> Unit) {
println("任务开始")
task()
println("任务结束")
}
使用:
kotlin
runTask {
println("正在下载文件")
}
输出结果:
text
任务开始
正在下载文件
任务结束
2. 封装登录逻辑
kotlin
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("用户名或密码错误")
}
}
调用:
kotlin
login(
username = "admin",
password = "123456",
onSuccess = {
println("登录成功")
},
onFailed = { message ->
println("登录失败:$message")
}
)
输出结果:
text
登录成功
十九、Lambda 和接口回调的关系
在 Android 中,很多接口回调可以用 Lambda 简化。
传统接口写法:
kotlin
interface LoginCallback {
fun onSuccess()
fun onFailed(message: String)
}
使用接口:
kotlin
loginManager.login("admin", "123456", object : LoginCallback {
override fun onSuccess() {
println("登录成功")
}
override fun onFailed(message: String) {
println("登录失败:$message")
}
})
如果改成 Lambda 参数:
kotlin
fun login(
username: String,
password: String,
onSuccess: () -> Unit,
onFailed: (String) -> Unit
) {
// 登录逻辑
}
调用就可以变成:
kotlin
login(
username = "admin",
password = "123456",
onSuccess = {
println("登录成功")
},
onFailed = {
println("登录失败:$it")
}
)
Lambda 可以减少很多模板代码。
二十、fun interface 函数式接口
Kotlin 中支持 fun interface,也叫函数式接口。
它的特点是:只能有一个抽象方法。
定义:
kotlin
fun interface OnItemClickListener {
fun onItemClick(position: Int)
}
使用匿名对象:
kotlin
val listener = object : OnItemClickListener {
override fun onItemClick(position: Int) {
println("点击了第 $position 项")
}
}
可以简写成 Lambda:
kotlin
val listener = OnItemClickListener { position ->
println("点击了第 $position 项")
}
这种写法适合只有一个回调方法的接口。
二十一、Lambda 和扩展函数结合
Kotlin 中经常把 Lambda 和扩展函数结合使用。
例如封装 View 点击事件:
kotlin
fun View.onClick(action: () -> Unit) {
setOnClickListener {
action()
}
}
使用:
kotlin
button.onClick {
Toast.makeText(this, "按钮被点击", Toast.LENGTH_SHORT).show()
}
防止重复点击:
kotlin
fun View.onSingleClick(interval: Long = 500, action: () -> Unit) {
var lastClickTime = 0L
setOnClickListener {
val currentTime = System.currentTimeMillis()
if (currentTime - lastClickTime > interval) {
lastClickTime = currentTime
action()
}
}
}
使用:
kotlin
button.onSingleClick {
println("执行点击逻辑")
}
二十二、Lambda 和作用域函数
Kotlin 中常见的作用域函数也大量使用 Lambda。
常见作用域函数:
kotlin
let
run
with
apply
also
1. let
let 常用于非空判断后执行逻辑。
kotlin
val name: String? = "张三"
name?.let {
println("姓名:$it")
}
Android 中常见写法:
kotlin
user?.let {
textView.text = it.name
}
2. apply
apply 常用于对象初始化。
kotlin
val user = User().apply {
name = "张三"
age = 18
}
等价于:
kotlin
val user = User()
user.name = "张三"
user.age = 18
Android 中常见写法:
kotlin
val intent = Intent(this, DetailActivity::class.java).apply {
putExtra("userId", 1001)
putExtra("userName", "张三")
}
3. also
also 常用于附加操作,比如打印日志。
kotlin
val names = mutableListOf("Kotlin", "Android").also {
println("当前列表:$it")
}
4. run
run 常用于执行一段代码并返回最后一行结果。
kotlin
val result = run {
val a = 10
val b = 20
a + b
}
println(result)
输出结果:
text
30
5. with
with 常用于对同一个对象进行多次操作。
kotlin
with(textView) {
text = "Hello Kotlin"
textSize = 16f
visibility = View.VISIBLE
}
二十三、Lambda 中的 this 和 it
在 Lambda 中,经常会看到 this 和 it。
| 关键字 | 常见场景 | 含义 |
|---|---|---|
it |
let、forEach、filter、map |
Lambda 的单个参数 |
this |
apply、run、带接收者 Lambda |
当前接收者对象 |
it 示例
kotlin
val names = listOf("张三", "李四")
names.forEach {
println(it)
}
这里 it 表示当前遍历到的元素。
this 示例
kotlin
val user = User().apply {
name = "张三"
age = 18
}
等价理解:
kotlin
val user = User().apply {
this.name = "张三"
this.age = 18
}
二十四、带接收者的 Lambda
带接收者的 Lambda 是 Kotlin 中比较高级但很常见的写法。
普通 Lambda:
kotlin
val block: (String) -> Unit = {
println(it)
}
带接收者的 Lambda:
kotlin
val block: String.() -> Unit = {
println(this)
}
区别:
| 类型 | 含义 |
|---|---|
(String) -> Unit |
接收一个 String 参数 |
String.() -> Unit |
在 String 对象的上下文中执行 |
示例:
kotlin
fun String.printSelf(block: String.() -> Unit) {
this.block()
}
"Hello".printSelf {
println(this)
}
输出结果:
text
Hello
Android 和 Compose 中会大量看到这种写法。
二十五、Android 中自定义 DSL 风格写法
带接收者 Lambda 可以写出类似 DSL 的代码。
kotlin
class DialogBuilder {
var title: String = ""
var message: String = ""
fun show() {
println("标题:$title")
println("内容:$message")
}
}
定义函数:
kotlin
fun showDialog(block: DialogBuilder.() -> Unit) {
val builder = DialogBuilder()
builder.block()
builder.show()
}
使用:
kotlin
showDialog {
title = "提示"
message = "确定要删除吗?"
}
输出结果:
text
标题:提示
内容:确定要删除吗?
这里的 DialogBuilder.() -> Unit 表示 Lambda 在 DialogBuilder 对象内部执行。
二十六、Lambda 在 RecyclerView 中的使用
传统 Adapter 点击事件常用接口回调,现在可以用 Lambda 简化。
kotlin
data class User(
val id: Int,
val name: String
)
Adapter 示例:
kotlin
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
}
}
使用:
kotlin
val adapter = UserAdapter(userList) { user ->
Toast.makeText(this, "点击了:${user.name}", Toast.LENGTH_SHORT).show()
}
这样就不需要单独定义 OnItemClickListener 接口。
二十七、Lambda 在协程中的使用
Android Kotlin 协程中也大量使用 Lambda。
kotlin
lifecycleScope.launch {
println("执行协程任务")
}
这里 {} 中的代码就是 Lambda。
kotlin
withContext(Dispatchers.IO) {
println("执行耗时任务")
}
这里 {} 也是 Lambda,表示在 IO 线程中执行的代码块。
二十八、Lambda 在 Jetpack Compose 中的使用
Jetpack Compose 中更是大量使用 Lambda。
kotlin
Button(
onClick = {
println("按钮被点击")
}
) {
Text("点击我")
}
这里有两个 Lambda:
kotlin
onClick = {
println("按钮被点击")
}
表示按钮点击时执行的逻辑。
kotlin
{
Text("点击我")
}
表示 Button 内部显示的内容。
再比如:
kotlin
Column {
Text("标题")
Text("内容")
}
Column {} 中的内容也是 Lambda。
二十九、Lambda 使用注意事项
1. Lambda 不要写得太长
不推荐:
kotlin
button.setOnClickListener {
// 大量业务逻辑
// 网络请求
// 数据处理
// UI 更新
}
推荐拆成函数:
kotlin
button.setOnClickListener {
login()
}
fun login() {
// 登录逻辑
}
2. 参数含义不清时,不要滥用 it
简单场景可以使用 it:
kotlin
userList.map {
it.name
}
复杂场景建议命名参数:
kotlin
userList.map { user ->
user.name
}
3. 多层 Lambda 注意 this 指向
如果嵌套较深,this 和 it 容易混淆,建议显式命名参数或拆分函数。
4. 需要 break / continue 时慎用 forEach
普通 for 可以使用:
kotlin
for (item in list) {
if (item == "Android") {
break
}
}
forEach 里不能直接像普通循环那样使用 break 和 continue。
需要中途退出时,优先使用普通 for。
5. 注意内存泄漏
在 Android 中,如果 Lambda 长时间持有 Activity 或 View 引用,可能导致内存泄漏。
例如把 Activity 的 Lambda 保存到全局对象中,就需要谨慎。
一般点击事件、局部集合操作问题不大,但长生命周期对象中保存短生命周期对象的 Lambda,要特别注意。
三十、Lambda 使用建议
| 场景 | 建议 |
|---|---|
| 点击事件 | 使用 Lambda 简化 |
| 集合遍历 | 使用 forEach、map、filter |
| 简单回调 | 使用 Lambda |
| 多状态回调 | 可以使用接口或密封类 |
| 复杂业务逻辑 | Lambda 中只调用函数,不堆大量代码 |
| 需要中途退出循环 | 优先使用普通 for |
| 单参数简单逻辑 | 可以使用 it |
| 复杂逻辑 | 建议给参数命名 |
| 对象初始化 | 使用 apply |
| 非空处理 | 使用 let |
| 附加操作 | 使用 also |
三十一、完整示例:使用 Lambda 封装登录逻辑
kotlin
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("用户名或密码错误")
}
}
}
使用:
kotlin
fun main() {
val loginManager = LoginManager()
loginManager.login(
username = "admin",
password = "123456",
onSuccess = { username ->
println("登录成功,欢迎 $username")
},
onFailed = { error ->
println("登录失败:$error")
}
)
}
输出结果:
text
登录成功,欢迎 admin
这个例子中:
| 参数 | 类型 | 作用 |
|---|---|---|
onSuccess |
(String) -> Unit |
登录成功时执行 |
onFailed |
(String) -> Unit |
登录失败时执行 |
三十二、完整示例:集合 Lambda 综合使用
kotlin
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)
}
输出结果:
text
[张三, 王五]
这个例子中:
| 函数 | 作用 |
|---|---|
filter |
筛选成年人 |
map |
把 User 转换成用户名 |
三十三、总结
Lambda 是 Kotlin 中非常重要的语法。
基本格式:
kotlin
{ 参数 ->
函数体
}
常见写法:
kotlin
val action = {
println("执行任务")
}
kotlin
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) |
| 作用域函数 | let、apply、also、run |
| 协程 | lifecycleScope.launch { } |
| Compose | Button(onClick = { }) { } |
最后记住一句话:
text
Lambda 的作用,就是把一段代码当作参数传递,让代码更简洁、更灵活。
在 Android Kotlin 开发中,熟练掌握 Lambda 之后,你会更容易理解点击事件、集合操作、高阶函数、协程以及 Jetpack Compose 的写法。