很多语言都支持Lambda表达式,Java在1.8才加入了对Lambda表达式的支持,而Kotlin语言在第一版就支持Lambda表达式。Lambda的语法结构就是函数式API的语法结构。
Lambda
Lambda通俗来讲就是一段可以作为参数传入的代码。
语法结构如下:
{参数名1:参数类型,参数名2:参数类型 -> 函数体}
最外层是一个带括号,是Lambda表达式范围,里面可传入参数,参数列表的结尾使用->表示函数体的开始,函数体可以使用{}包括任意多条代码,最后一行会自动作为lambda表达式的返回值。
Kotlin的集合中有很多函数式API,比较适合用来研究Lambda表达式。
val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape", "Watermelon")
var maxLengthFruit = ""
for (fruit in list) {
if (fruit.length > maxLengthFruit.length) {
maxLengthFruit = fruit
}
}
考虑上面的代码,用变量maxLengthFruit 存储list集合中长度最长的元素。这里如果使用了函数式API,可以进行这样的简化
val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape", "Watermelon")
val maxLengthFruit = list.maxBy { it.length}
这里的maxByOrNull 就是一个函数式API
但是我们通常是用Lambda语句时,并未使用上面的这种完整的语句,它有很多简化的写法。下面是对其简化写法的一些推导。
》
1、首先使用最基础的语法,可以这样写
val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape", "Watermelon")
val maxLengthFruit = list.maxBy() ({ fruit:String -> fruit.length })
这里的lambda表达式是标准的写法,将lambda表达式传入函数maxBy中作为参数。maxBy只是一个传入lambda作为参数的普通函数,函数内部会遍历集合并将值传入lambda表达式中。
2、Kotlin规定,当Lambda表参数是函数最后一个参数的时候,可以将Lambda表达式移动到函数括号外面
val maxLengthFruit = list.maxBy() { fruit:String -> fruit.length }
3、Lambda如果是唯一一个参数的话,可以将函数的括号省略
val maxLengthFruit = list.maxBy { fruit:String -> fruit.length }
4、由于Kotlin有优秀的类型推导机制,所以参数类型可以省略
val maxLengthFruit = list.maxBy { fruit -> fruit.length }
5、当只有一个参数的时候,可以不用指定参数名,可以使用it关键字代替
val maxLengthFruit = list.maxBy { it.length }
常用的函数式API
1、filter函数
filter函数接收一个lambda表达式作为参数,返回值为满足条件的一个新的集合。比如上面的过滤名字长度小于等于5的
val newList = list.filter { it.length <= 5 }
2、any函数
any函数用于判断集合中的元素是否有一个满足条件,返回值是一个Boolean类型的值。
val anyResult = list.any { it.length <= 5 }
存在则结果为true,否则为false。
3、all函数
all函数用于判断集合中的元素是否都满足条件
val allResult = list.all { it.length <= 5 }
所有都满足则结果为true,否则为false。
Java函数式API
如果在Kotlin中调用一个Java方法,并且方法接收一个Java单抽象方法接口参数,就可以使用函数式API。
Java单抽象方法指的是只有一个方法的接口。
以Runnable接口为例,Java中Runnable接口就是只有一个方法的接口,只有一个待实现方法run。
Java中创建线程的方法为:
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("new Tread");
}
}).start();
在Kotlin中写法为
Thread(object : Runnable {
override fun run() {
println("new Thread")
}
}).start
由于Kotlin中没有new关键字,内部类的写法如上,使用object关键字。
在Kotlin的语法中,可以进行简化
Thread(Runnable {
println("new Thread")
}).start
这里将具体的方法省略了,因为kotlin能够自动识别方法是哪一个,同时省略了对象声明。
除此之外,由于Java方法的参数列表有且仅有一个Java单抽象方法接口参数,可以将接口名省略。
Thread({
println("new Thread")
}).start
由之前的规则,lambda是最后一个参数的时候,可以将表达式移动到括号外面
Thread{
println("new Thread")
}.start
这样的调用都限定于用kotlin调用Java方法,并且单抽象方法接口是使用Java语言定义的。