学习kotlin的一些笔录5

15.Lambda编程基础

下面我们先用一个例子慢慢引出lambda,从一个水果集里找到字符最长的水果,ef:

val list = listOf("Apple", "Banana", "Pear")
var maxLength = ""
for(fruit in list){
    if(fruit.length > maxLength.length){
        maxLength = fruit
    }
}
println("max length is " + fruit)

但如果用集合的函数API,会更加简洁,ef:

val list = listOf("Apple", "Banana", "Pear")
var maxLength = list.maxBy{ it.length }
println("max length is "+ maxLength)

下面我们逐步来讲解一下为何可写得如此简洁,没错,会想到是lambda;lambda其实是 一小段 可作为参数传递的代码,完整语法结构为:

//函数体中可编写任意代码,但不建议太长,且函数体最后一行为lambda返回值
{ 参数名1:参数类型, 参数名2:参数类型 -> 函数体 }

前面的 函数API 语法结构似乎特殊,但其实maxBy就是个函数,只不过接收的是lambda,且它会在遍历集合时将每次遍历值作为参数传递给lambda,以此来找到最大值;了解后,下面我们套用lambda语法结构,将它传入maxBy中,ef:

val list = listOf("Apple", "Banana", "Pear")
val lambda = { fruit : String -> fruit.length }
val maxLength = list.maxBy(lambda)

但这显然啰嗦,可不需声明变量,直接将lambda传入maxBy中,ef:

val list = listOf("Apple", "Banana", "Pear")
val maxLength = list.maxBy({ fruit : String -> fruit.length })

由于kt中规定,当lambda为函数最后一个参数时,可将lambda移到函数括号外,ef:

val list = listOf("Apple", "Banana", "Pear")
val maxLength = list.maxBy() { fruit : String -> fruit.length }

由于lambda为函数唯一参数,所以括号也可省,ef:

val list = listOf("Apple", "Banana", "Pear")
val maxLength = list.maxBy { fruit : String -> fruit.length }

也由于kt的类型推导机制,lambda参数列大多情况可不必声明类型,简化得到,ef:

val list = listOf("Apple", "Banana", "Pear")
val maxLength = list.maxBy { fruit -> fruit.length }

最后,lambda参数列中只有一个参数,也不必声明参数名,用it关键字取代,最终得到,ef:

val list = listOf("Apple", "Banana", "Pear")
val maxLength = list.maxBy { it.length }

map函数式api,它用于将集合中的每个元素都映射成另外一个值,映射规则在lambda表达式中指定,最终生成新集合;下面将水果集的名变大写,ef:

fun main(){
    val list = listOf("Apple", "Banana", "Pear")
    val newList = list.map { it.toUpperCase() }
    for(fruit in newList){
        println(fruit)
    }
}
//打印结果如下:
APPLE
BANANA
PEAR

filter函数式API,过滤集合数据,可单独使用或配合集合使用,比如只想保留字符长度为5内的水果并转成大写,ef:

fun main(){
    val list = listOf("Apple", "Banana", "Pear")
    //此处先调用filter再调用map,而不是先调用map再调用filter(因这样做会先映射集合
    //所有元素再进行过滤,显然效率低了),先过滤后再进行集合内元素集合映射,效率提高
    val newList = list.filter { it.length <= 5 }.map{ it.toUpperCase() }
    for(fruit in newList){
        println(fruit)
    }
}
//打印结果如下
APPLE
PEAR

anyall 函数式API,any:判断集合内任意一元素满足条件,all:判断集合内所有元素满足条件,

ef:

fun main(){
    val list = listOf("Apple", "Banana", "Pear")
    val anyResult = list.any{ it.length <= 5 }
    val allResult = list.all{ it.length <= 5}
    println("anyFruit is " + anyFruit + ", allFruit is " + allFruit)
}
//打印如下
anyResult is true, allResult is false

以上是lambda语法结构和常用集合中的函数API,语法若掌握,其他函数API查阅文档即可掌握


java函数式API

上面我们已经学习了kt的函数式API,kt使用java方法也可进行函数式API,只不过有限制。如果kt调用了java函数,且该函数接收一个java单抽象方法接口(接口中只要一个抽象方法),ef:

public interface Runnable{
   void run();
}

根据上面讲解,对于任何一个java方法,只要它接收Runnable参数,就可以调用函数式API。对此会有很多方法都接收Runnable,对此多为线程实现该Runnable,以Thread为例子,ef:

new Thread(new Runnable(){
    @Override
    public void run(){
        System.out.println("running")
    }
}).start();

注意这里用到了匿名内部类,下面我们来翻译成kt版本,ef:

Thread(object : Runnable {
    override fun run() {
        println("running")
    }
}).start()

最终简化成如下,详细演化过程可回看我上文章中最后处关于object匿名内部类的实现,学习kotlin的一些笔录3_嗷喵喵没有吃鱼的博客-CSDN博客,ef: 

Thread{
    println("running")
}.start()

kt中会经常与java的调用,因为android sdk是用java编写的,下面再举例,android常用的点击接口,ef:

public interface OnClickListener{
    void onClick(View v);
}

点击具体实现如下,ef:

bt.setOnClickListener(new View.OnClickListener(){
    @Override
    public void onClick(View v){
        ...
    }
});

由于OnClickListener是java的单抽象方法接口,所以kt调用时可以用函数式API,对比上面的java调用则可以很简单,kt调用简化后如下,ef:

bt.setOnClickListener{
    ...
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值