Lambda编程
一.Lambda表达式和成员引用
简而言之:作为函数参数的代码块
{x : Int, y : Int -> x + y}//左半部分为参数,右半部分为函数体
如果lambda表达式是函数调用的最后一个实参,可以放到括号的外面
需要注意的是,kotlin不会仅限于访问final变量,在lambda内部也可以修改这些变量
成员引用:通过类名::成员名的方式,引用顶层函数时可以直接省略类名
val getAge = {person : Person -> person.age}
val getAge = Person::age
二.集合的函数式API
filter:从集合中移除你不需要的元素,但是不会改变这些元素
map:对集合中的每一个元素应用给定的函数并把结果收集到另一个集合中
all:对所有元素是否都满足判断
any:是否至少存在一个匹配的元素
groupBy:把列表转换成分组的map
API可以看源码去了解
三.惰性集合操作:序列
在使用集合的链式API时,每一次调用都会生成中间集合,使用序列可以避免创建临时中间对象
val people : List<Person> = ...
people.asSequence().filter().map().toList()
中间操作:返回另一个序列
末端操作:返回一个结果
如上代码所示,toList是末端操作,filter和map是中间操作
中间操作始终是惰性的,也就是说没有toList时,控制台不会有输出,末端操作触发了所有的延期计算
及早求值在整个集合上执行每个操作;惰性求职则逐个处理元素
四.使用Java函数式接口
当显式声明一个匿名对象时,每次调用都会生成一个新的对象;使用lambda时,如果没有访问任何来自定义它的函数的变量,则会重用同一个匿名类实例
五.带接收者的lambda:with和apply
(一)with函数
//不使用with时的效果
fun noWith(name : String) : String{
val stringBuilder = StringBuilder()
for (letter in 'A' .. 'Z')
stringBuilder.append(letter)
stringBuilder.append("hello")
return stringBuilder.toString()
}
//简单的使用
fun testWith(name : String) : String {
val stringBuilder = StringBuilder()
return with(stringBuilder){
append(name)
for (letter in 'A'..'Z')
this.append(letter)
toString()
}
}
//终极简化
fun testWithTwo(name :String) = with(StringBuilder()){
append(name)
for (letter in 'A'..'Z')
append(letter)
append("hello")
toString()
}
可以看出来with函数有两个参数,把第一个参数转换成作为第二个参数传给它的lambda的接收者,可以显式的通过this访问
(二)apply函数
apply函数和with比较接近,区别是apply始终会返回作为实参传递给它的对象,也就是接收者对象
改写with的例子如下,可以看出apply是被声明为一个扩展函数
fun testApply() : String = StringBuilder().apply {
for (letter in 'A'..'Z')
append(letter)
append("hello")
}.toString()