Lambda表达式和匿名函数-Kotlin

参考文章:一文吃透 Kotlin 中眼花缭乱的函数家族

名词解释

函数字面值:指不声明而是直接作为表达式传递的函数,lambda表达式和匿名函数都是函数字面值

一、Lambda表达式

1.1、语法形式如下:

Kotlin 复制代码
val doubleMax: (Int, Int) -> Int = { x, y ->
        val sum = x.coerceAtLeast(y)
        sum + sum
}
//或者 和属性一样可以省略函数类型,自行推断
val doubleMax = { x: Int, y: Int ->
        val sum = x.coerceAtLeast(y)
        sum + sum
}
  • 表达式总是括在花括号内
  • 函数体跟在->符号后面
  • 如果推断出该lambda的返回类型不是Unit,那么该lambda主体中的最后一个表达式的值会视为返回值

1.2、传递末尾的lambda表达式

按照Kotlin的惯例,如果函数的最后一个参数是函数,那么作为相应参数传入的lambda表达式可以放在圆括号之外:

Kotlin 复制代码
//高阶函数--可以将函数作为参数传递的函数
fun cal(x: Int, comparator: (Int, Int) -> Int): Int {
        return x * comparator(x, 2)
}
//调用
cal(100) { x, y -> x * y }
//结果:100*100*2 = 20000

如果该lambda表达式是函数的唯一参数,那么圆括号可以省略

Kotlin 复制代码
fun cal(comparator: (Int, Int) -> Int): Int {
        return 100 * comparator(100, 3)
}
//调用
cal{ x, y -> x * y }
//结果:100*100*3 = 30000

1.3、it:单个参数的隐式名称

如果一个lambda表达式只有一个参数,则定义表达式时可以省略参数名,该参数会隐式声明为it

Kotlin 复制代码
fun cal(comparator: (Int) -> Int): Int {
        return comparator(100)
}
//调用
cal { it * it }
//等价于(it可省略)
cal { it -> it * it }

1.4、lambda表达式返回值

可以使用限定返回语法从lambda显式返回一个值。否则,将隐式返回最后一个表达式的值

Kotlin 复制代码
val list = mutableListOf<Int>()
list.add(100)
list.add(-100)
val list2 = list.filter {
    return@filter it > 0
}
//等价于
val list2 = list.filter {
    it > 0
}

1.5 下划线用于未使用的变量

如果lambda表达式的参数未使用,可以用下划线取代其名称

Kotlin 复制代码
map.forEach { (_, value) -> println("$value!") }

1.6、表达式返回

在Kotlin中,只能对具名或者匿名函数使用正常的、非限定的return 来退出。要退出一个lambda表达式,需要一个标签。

在lambda表达式内部禁止使用裸return ,因为lambda表达式不能使包含它的函数返回

Kotlin 复制代码
val doubleMax = test@{ x: Int, y: Int ->
        val sum = x.coerceAtLeast(y)
        return@test sum + sum
    }

val doubleMax2 = { x: Int, y: Int ->
        val sum = x.coerceAtLeast(y)
        return sum + sum //错误
}

list.filter {
     return it > 0 //错误
}

但是如果lambda表达式是传给的函数是内联的,则return也可以内联。如下kotlin.collectionsforEach 函数是内联函数,可以这样:

Kotlin 复制代码
list.forEach {
     sum += it
     if (sum > 100) {
        return
     }
 }

二、匿名函数

上文的lambda表达式语法缺少一个能力------指定函数的返回类型的能力。大都是情况下是不需要的,返回类型可以自动推断出来。当然,如果确实需要显示指定,可以使用另一种语法:匿名函数

Kotlin 复制代码
fun(x: Int, y: Int):Int = x+y
//或者
fun(x: Int, y: Int): Int {
   return x + y //return不可省略
}

匿名函数看起来非常像一个常规函数声明,除了其名称省略了。

匿名函数的返回类型推断机制和正常函数一样:单表达式函数体的匿名函数将自动推断返回类型,但是具有代码块函数体的返回类型必须显式指定(Unit返回类型不需要指定)

三、Function接口

Kotlin decompile转换成Java文件后,可以看出lambda表达式和匿名函数本质上对应的是Function接口。lambda表达式和匿名函数会被转换成一个个Function 接口对象

Kotlin 复制代码
package kotlin.jvm.functions

/** A function that takes 0 arguments. */
public interface Function0<out R> : Function<R> {
    /** Invokes the function. */
    public operator fun invoke(): R
}
/** A function that takes 1 argument. */
public interface Function1<in P1, out R> : Function<R> {
    /** Invokes the function with the specified argument. */
    public operator fun invoke(p1: P1): R
}
/** A function that takes 2 arguments. */
public interface Function2<in P1, in P2, out R> : Function<R> {
    /** Invokes the function with the specified arguments. */
    public operator fun invoke(p1: P1, p2: P2): R
}
...
public interface Function22<...> : Function<R> {
    /** Invokes the function with the specified arguments. */
    public operator fun invoke(...): R
}

最多支持22个参数,当然我们也可以自己扩展

四、闭包

闭包概念:参考文章

函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起构成闭包。

周围环境应该如何理解呢,可以理解为函数所处的外部作用域中定义的各个自由变量,这个作用域可能是另一个函数或块级作用域。二者捆绑在一起构成的闭包使得函数内部可以对外部作用域定义的变量进行访问。

Lambda表达式或者匿名函数(以及局部函数)可以访问闭包,即在外部作用域中声明的变量。 在 lambda 表达式中可以修改闭包中捕获的变量。示例:

Kotlin 复制代码
fun main() {
        
    val list = mutableListOf<Int>()
    list.add(2)
    list.add(3)
    list.add(-1)
    var sum = 0
    list.filter { it > 0 }.forEach {
    //这里可以访问sum属性
             sum += it
    }

}
相关推荐
jinanwuhuaguo1 小时前
(第二十七篇)OpenClaw四月的演化风暴:OpenClaw 2026年4月全版本更新的文明级解读
大数据·人工智能·架构·kotlin·openclaw
随遇丿而安1 小时前
第2周:`EditText` 不只是输入框,它是 Android 输入体验的第一道门
android
我命由我123451 小时前
Kotlin 开发 - lateinit 关键字
android·java·开发语言·kotlin·android studio·android-studio·android runtime
一起搞IT吧1 小时前
Android性能系列专题理论之十:systrace/perfetto相关指标知识点细节含义总结
android·嵌入式硬件·智能手机·性能优化
小书房6 小时前
Kotlin的by
android·开发语言·kotlin·委托·by
jinanwuhuaguo6 小时前
(第二十八篇)OpenClaw成本与感知的奇点——从“Token封建制”到“全民养虾”的本体论地基
android·人工智能·kotlin·拓扑学·openclaw
xxjj998a7 小时前
Laravel4.x核心特性全解析
android·mysql·laravel
JoshRen7 小时前
2026教程:在Android Termux中集成Gemini 3镜像站实现移动端文档自动处理与摘要生成(附国内免费方案)
android
诸神黄昏EX8 小时前
Android Google KEY
android
一起搞IT吧8 小时前
Android性能系列专题理论之十一:block IO问题分析思路
android·嵌入式硬件·智能手机·性能优化