一篇文章让你了解Lambda编程

首先来看看书上的介绍
Lambda 表达式,或简称 lambda ,本质上就是可以传递给其他函数的 小段代码 有了 lambda ,可以轻松地把通用的代码结构抽取成库函数, Kotlin 标准库就大量 使用了它们。
Lambda  其实就是作为函数参数的代码块
在你的代码中存储和传递一小段行为是常有的任务 例如,你常常需要表达像这样的想法:“当一个事件发生的时候运行这个事件处理器”又或者是“把这个操作应用到这个数据结构中所有的元素上”。在老版本的 Java 中,可以用匿名内部来实现。这种技巧可以工作但是语法太唠唆了。函数式编程提供了另外一种解决问题的方法:把函数当做值来对待。 以直传递函数,而不需要先声明一个类再传递这个类的实例 使用 lambda 表达式之后代码会更加简洁。都不需要声明函数了 相反,可以高效地直接传递代码块作数参数。
        
是不是云里雾里的,不急,首先来看看一个简单的例子。本文通过java和kotlin两种写法来说明Lambda编程 
我们用最常见的点击事件来举例:
java :
button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        
    }
});

kotlin :

button.setOnClickListener { 
    
}

是不是觉得少了很多行代码,整个代码整洁很多,一句话就直接代替了java中的匿名内部类的写法。这就是lambda编程。下面,我们来先了解下lambda编程

先看看  la mbda  表达式的经典用途:和集合一 起工作

1. Lambda 和集合

先创建一个实例:person类  包含名字在和年龄

data class Person(val name: String,val age:Int)

假设我们有一个列表

val people = listOf(Person("小明",20),Person("小红",18),Person("小芳",17))

现在我们要从这个列表中找出年纪最大的那个人

java:

fun finTheOldest(people: List<Person>) {
    var maxAge = 0
    var theOldest: Person? =null
    for (person in people) {
        if (person.age > maxAge) {
            maxAge = person.age
            theOldest = person
        }
    }
    println(theOldest)
}

写一个循环的方法,传入这个列表,通过不断对比对比找到最大的那个数。这么写的代码量多,且容易报错。让我们看看kotlin怎么实现

kotlin:

people.maxBy{it.age}

kotlin就一行代码,为什么呢?因为由于lambda的帮助,在Kotlin中对集合很多的操作都被封装在了库里,避免了很多重复代码。maxBy{}实际上就是一个库函数

花括号的it.age就是实现这个逻辑的lambda,它接收一个集合中的元素作为实参(使用 it 引用它)并且返回用来比较的值 这个例子中集合元素是 Person 对象用来比较的是存储在其 age 属性中的年龄。就相当于 java中的finTheOldest()这个方法。

这个函数是简化后的函数,我们先看看lambda的语法,等下再回来简化这个函数。

写法就是

val sum = {x:Int,y:Int-> x+y}   

转换成java就是

public int sum(int x,int y){
    return x+y;
}

x和y是传入的参数,x+y就是函数体。

那么我们来简化上面找最大年纪的例子,如果不用任何简明语法来写就是

people.maxBy ({ p:Person -> p.age })
这段代码一目了然:花括号中的代码片段是 L ambda 表达式,把它作为实参传给函数。这个lambda 接收一个类型为 Person 的参数并返回它的年龄。
首先,我们先把括号提出来, Kotlin 有这样 一种语法约定,如果 lambda 表达式是函数调用的最后一个实参,它可以放到括号的外边。这个例子中, lambda 是唯一的实参,所以可以放到括号的后边:
people.maxBy (){ p:Person -> p.age }
lam bda 是函数唯一的实参时,还可以去掉调用代码中的空括号对:
people.maxBy { p:Person -> p.age }

如果lambda表达式参数的类型可以被推导出来,可以直接省略参数类型

people.maxBy { p -> p.age }

其参数类型始终和集合的元素类型相同, 编 译器知道你是对 Per so 对象的集合调用 maxBy 函数,所以它能推断 lambda 参数也会是 Person 类型。

如果当前 上下文期望的是只有一个参数 lambda 且这个参数的类型可以推断出来,则可以 使用默认参数名称 it 代替命名参数
people.maxBy{it.age}

注意:并不是所有lambda都能简写的。

举个例子:

val getAge = {p:Person->p.age}

你用变量存储的这个lambda,则没有上下文推断参数类型的,所以你必须指定参数。

2.在作用域中访问变量

当在函数内声明一个匿名 内部类的时候,能够在这个匿名类内部引这个函数的 参数和局部变量。 也可以用 lambda 做同样的事情 如果在函数内部使用 lambda, 也可以访问这个函数的参数,还有在 lambda 之前 定义的局部变量。
我们用标准库函数 forEach 来展示这种行为:
 
      

在函数的内部使用lambda时,可以访问在lambda前定义的局部变量

与Java不一样的是,Kotlin中的在lambda内部可以访问非final变量,甚至可以修改他们。我们称这些变量被lambda捕捉

3. 成员引用

你己经看到 lambda 是如何让你 把代 码块作为参数传递给函数的 。但是 如果你要当作参数传递的代码己经被定义成了函数,该怎么办?当然可以传递一个调用这个函数的 L mbda ,但这样做有点多余。那么你能直接传递函数吗?
例如:
val getAge = Person :: age
这种表达式称为成员 引用, 它提供了简明语法,来创建一 个调用单个方法或访问单个属性的函数值。双冒号把类名称与你要引用的成员( 个方法或者一 个属 性)名称隔开,如图所示

那么,这是一个更简洁的 Lambd 表达式,它做同样的事情:

val getAge = { person : Person -> person.age }
注意,不管你引用的是函数还是属性,都不要在成员引用的名称后面加括号
成员引用和调用该函数的 lambda 具有 样的类型,所以可以互换使用:
people.maxBy (Person :: age)
还可以引用顶层函数(不是类的成员):
fun salute() = println("Salute !")
run (::salute)
如果 L ambda 要委托给一 个接收多个参数 的函数,提供成 引用代 替它将会非常方便:

也可以用构造方法引用存储或者延迟执行创建类实例的动作

4.分析开头的点击事件

学完概念,我们回到开头讲的按钮点击事件,先写一个未做任何简化的点击事件

button?.setOnClickListener(object :View.OnClickListener{
    override fun onClick(v: View?) {
        TODO("点击事件")
    }
})
先简化方法
button?.setOnClickListener(View.OnClickListener{
    TODO("点击事件")
})
接下来简化接口
button?.setOnClickListener({
    TODO("点击事件")
})
最后去掉括号,就和我们上面写的一样了

button?.setOnClickListener{
    TODO("点击事件")
}

5.集合的函数式API

函数式编程风格在操作集合时提供了很多优势。大多数任务都可以通过库函数 完成,来简化你的代码。

下面只举例几个例子:

filter函数:

遍历集合并选出应用给定lambda后会返回true的那些元素

//使用filter函数,返回偶数集合
val datas = listOf(1, 2, 3, 4, 5)
println(datas.filter { it % 2 == 0 })

filter函数可以从集合中过滤我们不想要的元素,但是并不会改变这些元素

map函数:

对集合中的每一个元素应用给定的函数,并将结果收集到一个新集合。

//将传入的数字列表,变成他们的平方的列表
val list = listOf(1, 2, 3)
println(list.map { it * it })

  • 14
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值