Kotlin基础学习(十五)—— lambda(1)

Lambda表达式(简称 lambda):本质上是可以传递给其他函数的一小段代码

一、lambda表达式的语法

1、Kotlin 的 lambda 表达式始终用花括号包围
{x:Int, y:Int -> x+y}  //lambda表达式的语法, x和y是参数,x+y是函数体,->箭头把实参列表和lambda的函数体隔开
2、可将 lambda 表达式存储在一个变量中,把这个变量当作普通函数对待
val sum = {x:Int, y:Int -> x+y} 
println(sum(1,2))
3、lambda 的简化写法

代码:

people.maxBy{it.age}

其全面的写法如下:

people.maxBy({ p:Person -> p.age }) //p是参数,p.age是函数体

接着将最全面的写法一步步简化:

1)Kotlin语法约定:如果lambda表达式是函数调用的最后一个实参,它可以放到括号的外边。

people.maxBy(){p:Person->p.age}

2)Kotlin语法约定:当lambda时函数唯一的实参时,可以去掉调用代码中的空括号对

people.maxBy{p:Person->p.age}

3)maxBy函数的参数类型始终和集合的元素类型相同,所以编译器可以根据people(Person对象的集合)推断出 maxBy 参数类型是 Person。所以,参数类型可省略

people.maxBy{p->p.age}

4)使用默认参数名称 it 来代替命名参数 p

people.maxBy{it.age}

使用 it 的场景:如果当前上下文期望的是只有一个参数的 lambda 且这个参数的类型可以推断出来时使用。

如果用变量存储 lambda,那么就没有可以推断出参数类型的上下文,这时必须显式地指定参数类型:

val getAge = { p:Person -> p.age }
people.maxBy(getAge)
4、成员引用

成员引用的格式:类名称 + 双冒号 + 要引用的成员(方法或属性)名称

注意,即使引用方法也不能在方法名后面加括号

引入成员引用的目的:lambda 可以将代码块作为参数传递给函数,但是如果这个代码块已经被定义成了函数,这时可使用成员引用,将函数转换成一个值。

1)

val getAge = Person::age   //这种表达式称为 成员引用

等同于 lambda 表达式:

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

2)

people.maxBy(Person::age)

等同于 lambda 表达式:

people.maxBy{person:Person->person.age}

3) 还可以引用顶层函数(不是类的成员)

fun sun() = println("sun")
fun main(args:Array<String>){
    run(::sun)  //引用顶层函数
}

4)将 lambda 委托给一个接收多个参数的函数

fun sendEmail(name:String,message:String){
    println("发送给${name}的信息为$message")
}
fun main() {
    
    val action = {
        name:String,message:String ->
            sendEmail(name, message)
    }
    val actionNext = ::sendEmail

    action("Java","你好啊!")
    actionNext("Kotlin","你好啊!")
}

这里不是很明白,明明可以直接调用函数,为什么还要借助lambda呢(之后再说)

5)可以用 构造方法引用 存储 或 延期执行 创建类实例的动作

data class Person(val name:String, val age:Int)
fun main(args:Array<String>){
	val createPerson = ::Person
    val p = createPerson("Alice", 29)
    println(p)
}

6)还可引用扩展函数

data class Person(val name:String, val age:Int)
fun Person.isAdult():Boolean = age>=18
fun main(args:Array<String>){
    val createPerson = ::Person
    val p = createPerson("Alice", 29)
    val predicate = Person::isAdult  //引用扩展函数
    println(predicate(p))
    println(p.isAdult())
}

二、lambda 主要用途

1、lambda 被当作只有一个方法的匿名对象的替代品
//Java  使用匿名对象来实现事件监听器
button.setOnClickListener(new OnClickListener(){  //相当于实现了一个接口的匿名类
    @Override
    public void onClick(View v){
        //点击后执行的动作
        ... ...
    }
})

    在上述代码中 button.setOnClickListener 的参数是通过匿名内部类得到的,传递该参数的目的是调用其实现的 onClick 方法,可以理解为,由于 Java 不允许传递方法,所以将 onClick 方法包进 OnClickListener 类型的对象中来进行传递。

    而在 Kotlin 中,函数的参数也可以是函数类型的。

//Kotlin 使用lambda实现事件监听器
button.setOnClickListener{
    //点击后执行的动作
    ... ...
}

这种方式可以工作的原因是 OnClickListener 接口只有一个抽象方法,即OnClickListener 接口为函数式接口。Kotlin 允许在调用接收 函数式接口 作为参数的方法时使用 lambda。

函数式接口(SAM接口,SAM表示单抽像方法):只有一个抽象方法的接口

2、lambda和集合一起工作

Kotlin 标准库中和函数有关的API:

1)filter

filter函数遍历集合并选出应用给定lambda后会返回true的那些元素,得到一个新集合,只包含输入集合中满足判断式的元素(注意,filter并不会改变这些元素)

val list = listOf(1,2,3,4)
println(list.filter{ it % 2 == 0 })  //得到一个新的集合,只包含偶数

2)map

对集合中的每一个元素应用给定的函数并把结果收集到一个新集合(注意,map会涉及到元素的变化)

val list = listOf(1,2,3,4)
println(list.map{it*it})  //1,4,9,16
val people = listOf(Person("Alice", 29), Person("Bob", 31))
println(people.map{it.name})  //[Alice, Bob]
//或者用成员引用
println(people.map(Person::name))  //[Alice, Bob]
people.filter{ it.age>30 }.map(Person::name)   //打印年龄超过30岁的人的名字

3)all

判断是否集合中的所有元素都满足判断式

val people = listOf(Person("Alice", 29), Person("Bob", 31))
val canBeInClue27 = { p:Person -> p.age<=27 }
println(people.all(canBeInClue27))

4)any
检查集合中是否至少存在一个匹配的元素

val people = listOf(Person("Alice", 29), Person("Bob", 31))
val canBeInClue27 = { p:Person -> p.age<=27 }
println(people.any(canBeInClue27))

5)count
集合中有多少个元素满足判断式

val people = listOf(Person("Alice", 29), Person("Bob", 31))
println(people.count(canBeInClue27))

6)find
找到集合中的一个满足判断式的元素,如果有多个匹配的元素就返回其中第一个元素

val people = listOf(Person("Alice", 29), Person("Bob", 31))
println(people.find(canBeInClue27))

7)groupBy
把列表转换成分组的map

val people = listOf(Person("Alice", 31), Person("Bob", 29), Person("Carol", 31))
println(people.groupBy{it.age})

得到的结果是一个Map<Int, List< Person >>

{29=[Person(name=Bob, age=29)], 31=[Person(name=Alice, age=31), Person(name=Carol, age=31)]}

8)flatMap 和 flatten

flatMap 做了两件事:① 首先根据作为实参给定的函数(即lambda表达式)对集合中的每个元素做变换(或者说映射);② 然后把多个列表合并(或者说平铺)成一个列表

class Book(val title:String, val authors:List<String>)
books.flatMap{it.authors}.toSet() 
val strings = listOf("abc", "def")
println(strings.flatMap{it.toList()})  //{a,b,c,d,e,f}

Kotlin标准库中关于集合操作的函数还有很多,这里只介绍这些

参考:
《Kotlin实战》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值