lambda 表达式与匿名函数是“函数字面值”,即未声明的函数, 但立即做为表达式进行传递。在Java 8中也开始支持Lambda表达式。
Lambda表达式语法
lambda 表达式由花括号括起来, 包含完整语法形式的参数声明,参数声明有可选的类型标注, 函数体跟在一个 ->
符号之后。如果可以推断出的该lambda表达式的返回类型不是 Unit,那么该 lambda 主体中的最后一个表达式(主体可能只有一个表达式)会视为返回值。
// 格式
{<param[: type]>[...] -> body}
// 示例
val sum: (Int, Int) ->Int = {x: Int, y: Int -> x + y} // 前面是个函数类型变量,等号后面是lambda表达式用来初始化该变量
- 对于以上的示例,
x
和y
是参数,x + y
是主体(只有一个表达式),该表达式返回值类型不是Unit,所以最后一个表达式(x + y
)会视为lambda表达式的返回值;sum
是函数类型变量,函数类型变量中已经声明了参数和返回值的类型,那么使用lambda初始化该变量时,可以忽略掉lambda表达式中参数列表中参数的类型,可简写成val sum: (Int, Int) -> Int = {x, y -> x + y}
Lambda表达式初始化函数类型参数
函数类型可以通过Lambda表达式进行初始化
val sum: (Int, Int) -> Int = {x: Int, y: Int -> x + y}
sum
是函数类型变量,函数类型变量中已经声明了参数和返回值的类型,那么使用lambda初始化该变量时,可以忽略掉lambda表达式中参数列表中参数的类型,可简写成val sum: (Int, Int) -> Int = {x, y -> x + y}
Lambda表达式作为高阶函数的参数
// com函数的第三个参数z是一个函数类型的变量
fun com(x: Int, y: Int, z: (Int, Int) -> Int): Int {
return z(x, y)
}
println(com(3, 55, {x: Int, y: Int -> x + y})) // lambda表达式作为高阶函数的参数
println(com(3, 55){x: Int, y: Int -> x + y}) // 如果高阶函数的最后一个参数是lambda表达式,可以将lambda表达式放到参数括号后面,这种语法也叫做拖尾lambda表达式
val sum = {x: Int, y: Int -> x + y} // 定义lambda表达式是,如果无法推断出参数的类型,参数类型不可省略
println(com(3, 55, sum)) // 如果高阶函数最后一个参数是lambda表达式变量,不可放在参数括号后面
Lambda单个参数的隐式名称:it
只有一个参数在 lambda 表达式是很常见的,如果编译器自己可以识别出签名,也可以不用声明唯一的参数并忽略 ->
。 该参数会隐式声明为 it
:
- 表达式只有一个参数
- 表达式的签名可以被编译器推断出
- 在主体中,参数只能用
it
表示
val validate: (Int) -> Boolean = {it > 0}
上面的例子中,只有一个参数,根据函数类型的声明,编译器可以识别出lambda表达式的签名,所以省略了lambda表达式中的参数和
->
,上面表达式等同于val validate: (Int) -> Boolean = {x: Int -> x > 0}
从lambda表达式中返回一个值
- 如果lambda表达式的返回值不是
Unit
,又没有指定返回值,默认将最后一个表达式作为返回值。
val sum: (Int, Int) -> Int = {x, y -> x + y } // 默认返回值是`x + y`这个表达式的结果
- lambda 表达式语法没有指定函数的返回类型的能力,一般是可以通过表达式进行推断,如果无法推断,可以使用匿名函数来实现(匿名函数的函数体可以是语句,也可以是代码块)
代码块作为lambda表达式的主体部分
上面提到lambda表达式没有指定返回值类型的能力,那么需要返回特定类型的值,就需要在主体代码中实现。
- 用
run<R>{}
进行包裹的代码块作为lambda表达式主体实现指定返回值类型,泛型R
是可选,如果没有返回值,可以不指明类型(默认Unit),如果有返回值可指定返回值类型,在代码块中,返回值无需return
关键字,最有一个表达式语句的结果即为返回值。
val sum = {x: Int, y: Int -> run<Int> {
val s = x + y
// 返回值时不能用return,最后一个表达式为返回值,所以这里必须使用if-else的语句组合(不能省去else,否则最终的返回值都是s)
if(s < 0) {
0
} else {
s
}
}}
- 使用匿名函数作为lambda表达式主体实现指定返回值类型,应为函数是可以指定返回值类型的,当使用函数作为lambda表达式主体时,也就为lambda表达式指定了返回值
// 匿名函数作为lambda表达式的主题,在匿名函数中指定返回值
val sum = {x: Int, y: Int -> fun(x: Int, y: Int): Int {
val s: Int = x + y
if(s < 0) {
return 0
}
return s
}}