1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > Android开发——Kotlin语法之Lambda表达式

Android开发——Kotlin语法之Lambda表达式

时间:2020-11-23 13:48:43

相关推荐

Android开发——Kotlin语法之Lambda表达式

Lambda表达式在C++/Java中都支持,作为一种辅助语句。但是在Kotlin中,Lambda表达式的功能极其强大。

简化是Kotlin语言的思想之一,而在Lambda表达式的学习之中,该思想将会贯穿其中

Lambda入门编程

集合的函数式API是用来入门Lambda编程的绝佳示例,不过在此之前,我们得先学习创建集合的方式才行

集合的创建

在Kotlin中,提供了一个listof()的内置函数来帮助我们创建一个集合,用法如下:

val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape")

这里,我们创建了一个水果的集合。值得注意的是,我们使用的listof()函数创建的是一个不可变的集合,该集合只能用于读取,我们无法对集合进行添加、修改或删除操作。如果我们需要创建一个可变的集合,我们可以使用mutableListof()函数。使用方法与listof相同。

集合的函数式API

首先我们来思考一个需求,如何在一个水果集合里面找到单词最长的那个水果?在Kotlin中,我们可以写出如下代码:

val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape", "Watermelon")val maxLengthFruit = list.maxBy {it.length }println("max length fruit is " + maxLengthFruit)

这里使用了函数式APImaxBy()。maxBy是一个函数,只不过它接收的是一个Lambda类型的参数,并且会在遍历集合时将每次遍历的值作为参数传递给Lambda表达式。maxBy函数的工作原理是根据我们传入的条件来遍历集合,从而找到该条件下的最大值,比如说想要找到单词最长的水果,那么条件自然就应该是单词的长度了。因此,我们可以推断出it.lenth就是一个Lambda表达式。更确切地说,这是简化后的Lambda表达式。

Lambda表达式的语法结构

首先来看一下Lambda的定义,如果用最直白的语言来阐述的话,Lambda就是一小段可以作为参数传递的代码。从定义上看,这个功能就很厉害了,因为正常情况下,我们向某个函数传

参时只能传入变量,而借助Lambda却允许传入一小段代码,其语法结构如下:

{参数名1: 参数类型, 参数名2: 参数类型 -> 函数体}

值得注意的是,Lambda表达式的最后一行代码会自动作为Lambda表达式的返回值。

Lambda表达式的简化

这一部分,我们来介绍Lambda表达式简化的一些规则。

对于找到单词最长的水果,我们一开始可以写出这样的代码:

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

首先,我们不需要专门定义一个lambda变量,而是可以直接将lambda表达式传入maxBy函数当中,因此第一步简化如下所示:

val maxLengthFruit = list.maxBy({fruit: String -> fruit.length })

简化规则1:当Lambda参数是函数的最后一个参数时,可以将Lambda表达式移到函数括号的外面

根据简化规则1,我们继续将该行代码简化:

val maxLengthFruit = list.maxBy() {fruit: String -> fruit.length }

简化规则2:如果Lambda参数是函数的唯一一个参数的话,还可以将函数的括号省略

根据简化规则2,我们继续将该行代码简化:

val maxLengthFruit = list.maxBy {fruit: String -> fruit.length }

简化规则3:由于Kotlin出色的类型推导机制,Lambda表达式中的参数列表其实在大多数情况下不必声明参数类型

根据简化规则3,我们继续将该行代码简化:

val maxLengthFruit = list.maxBy {fruit -> fruit.length }

简化规则4:当Lambda表达式的参数列表中只有一个参数时,也不必声明参数名,而是可以使用it关键字来代替

根据简化规则3,我们继续将该行代码简化:

val maxLengthFruit = list.maxBy {it.length }

于是乎,我们就得到了与开头我们提供的代码一模一样的代码。

其它的函数式API

map函数:它用于将集合中的每个元素都映射成一个另外的值,映射的规则在Lambda表达式中指定,最终生成一个新的集合。

如下所示的代码是将所有的水果名都变成大写模式:

fun main() {val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape", "Watermelon")val newList = list.map {it.toUpperCase() }for (fruit in newList) {println(fruit)}}

filter函数:用来过滤集合中的数据,过滤的规则在Lambda表达式中指定

如下所示的代码是保留5个字母以内的水果,并将其单词全部大写:

fun main() {val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape", "Watermelon")val newList = list.filter {it.length <= 5 }.map {it.toUpperCase() }for (fruit in newList) {println(fruit)}}

any函数:用于判断集合中是否至少存在一个元素满足指定条件,条件在Lambda表达式中指出

all函数:用于判断集合中是否所有元素都满足指定条件,条件在Lambda表达式中指出

any函数和all函数的用法如下:

fun main() {val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape", "Watermelon")val anyResult = list.any {it.length <= 5 }val allResult = list.all {it.length <= 5 }println("anyResult is " + anyResult + ", allResult is " + allResult)}

Kotlin调用Java方法

在Kotlin中调用Java方法时也可以使用函数式API,只不过这是有一定条件限制的。具体来讲,如果我们在Kotlin代码中调用了一个Java方法,并且该方法接收一个Java单抽象方法接口参数,就可以使用函数式API。Java单抽象方法接口指的是接口中只有一个待实现方法,如果接口中有多个待实现方法,则无法使用函数

式API。

Java原生API中有一个最为常见的单抽象方法接口——Runnable接口。这个接口中只有一个待实现的run()方法,定义如下:

public interface Runnable {void run();}

根据前面的讲解,对于任何一个Java方法,只要它接收Runnable参数,就可以使用函数式API。那么什么Java方法接收了Runnable参数呢?这就有很多了,不过Runnable接口主要还

是结合线程来一起使用的,因此这里我们就通过Java的线程类Thread来学习一下。

Thread类的构造方法中接收了一个Runnable参数,我们可以使用如下Java代码创建并执行一个子线程:

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

注意,这里使用了匿名类的写法,我们创建了一个Runnable接口的匿名类实例,并将它传给了Thread类的构造方法,最后调用Thread类的start()方法执行这个线程。

而如果直接将这段代码翻译成Kotlin版本,写法将如下所示:

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

Kotlin中匿名类的写法和Java有一点区别,由于Kotlin完全舍弃了new关键字,因此创建匿名类实例的时候就不能再使用new了,而是改用了object关键字。这种写法虽然算不上复杂,但是

相比于Java的匿名类写法,并没有什么简化之处。但是别忘了,目前Thread类的构造方法是符合Java函数式API的使用条件的,下面我们就看看如何对代码进行精简,如下所示:

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

这段代码明显简化了很多,既可以实现同样的功能,又不会造成任何歧义。因为Runnable类中只有一个待实现方法,即使这里没有显式地重写run()方法,Kotlin也能自动明白Runnable后面的Lambda表达式就是要在run()方法中实现的内容。

另外,如果一个Java方法的参数列表中有且仅有一个Java单抽象方法接口参数,我们还可以将接口名进行省略,这样代码就变得更加精简了:

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

不过到这里还没有结束,和之前Kotlin中函数式API的用法类似,当Lambda表达式是方法的最后一个参数时,可以将Lambda表达式移到方法括号的外面。同时,如果Lambda表达式还是方法的唯一一个参数,还可以将方法的括号省略,最终简化结果如下:

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

例子

在Kotlin中调用Java函数式API最经典的例子当属点击事件的接口了。

Android中有一个极为常用的点击事件接口OnClickListener,其定义如下:

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

可以看到,这又是一个单抽象方法接口。假设现在我们拥有一个按钮button的实例,然后使用Java代码去注册这个按钮的点击事件,需要这么写:

button.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {}});

而用Kotlin代码实现同样的功能,就可以使用函数式API的写法来对代码进行简化,结果如下:

button.setOnClickListener {}

而最后这段给按钮注册点击事件的代码,将会在Android开发时经常用到。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。