lambda java kotlin,Kotlin之Lambda编程

1、Lambda的定义

Lambda就是一小段可以作为参数传递的代码。正常情况下,我们向某个函数传参时只能传入变量,而借助Lambda却能传入一小段代码,那么多长的代码才能算一小段代码,Kotlin不建议很长的代码,可读性太差。

接下来我们看下,Lambda表达式的语法结构:

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

这是Lambda表达式最完整的语法结构。

1、首先最外层一对大括号。

2、如果有参数传入Lambda表达式,我们还需要声明参数列表。

3、参数列表的结尾使用->符号,表示参数列表的结束以及函数体的开始,函数体中代码长度不限,并且最后一行代码表示Lambda表达式的返回值。

2、集合的函数式API

2.1、maxBy

集合的函数式API有很多个,这里并不打算讲解所有的函数式API的用法,而是重点学习函数式API的语法结构,也就是Lambda表达式的语法结构。

先看一个需求:如何从List集合中找到单词最长的那个水果。

val list = arrayListOf("Apple", "Banana", "Orange", "Pear")

list.add("Watermelon")

var maxLengthFruit = ""

for (fruit in list) {

if (fruit.length >= maxLengthFruit.length)

maxLengthFruit = fruit

}

println("单词最长的水果:"+maxLengthFruit)

代码很简单,如果使用集合函数式API来实现的会更简单

val list = arrayListOf("Apple", "Banana", "Orange", "Pear")

list.add("Watermelon")

var maxLengthFruit = list.maxBy { it.length }

println("单词最长的水果:" + maxLengthFruit)

list.maxBy { it.length }直接看这个还是很难理解的,maxBy就是一个普通的函数,只不过它接收的是一个Lambda类型的参数,并且会在遍历集合时将每次遍历的值作为参数传递给Lambda表达式。maxBy函数工作原理是根据我们传入的条件来遍历集合,从而找到该条件下的最大值,比如我们想找到单词最长的水果,那么条件自然是单词的长度。

理解了maxBy的工作原理, 我们就先用标准的Lambda的语法结构作为参数,传递给maxBy函数。

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

val lambda = { fruit: String -> fruit.length }

//注意这里是小括号,括号中接收的Lambda参数

val maxLengthFruit = list.maxBy(lambda)

println("单词最长的水果:" + maxLengthFruit)

可以看到maxBy中接收的是一个Lambda参数而已,并且这个Lambda参数是完全按照Lambda的标准结构定义的,这段代码虽然可以正常工作,但是需要简化的点很多,下面我们一步步简化。

1、首先我们不需要专门定义一个lambda变量,可以将lambda表达式传入maxBy函数中

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

2、Kotlin规定,当Lambda是函数的最后一个参数时,可以将Lambda表达式移到函数的括号外面

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

3、如果Lambda是函数的唯一参数的话,可以省略函数的括号

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

4、由于Kotlin拥有出色的类型推导机制,所以Lambda的参数列表大多数情况下不需要声明参数类型

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

5、最后当Lambda表达式只有一个参数时,也没必要声明参数名称,可以用it代替

val maxLengthFruit = list.maxBy{ it.length }

经过一步步推导,终于简化完成了。接下来我们学习下几个集合中标常用的函数式API。

2.2、集合中的map函数

集合中的map函数的作用:是将集合中的每个元素映射成另外的值,映射的规则是在Lambda表达式中指定的,最终生成一个集合。比如这里我们想让水果名变成大写的

val list = listOf("apple", "orange")

val newList = list.map { it.toUpperCase() }

for (fruit in newList){

println("fruit::"+fruit)

}

map函数的功能非常强大,它可以按照我们的要求对集合中的元素进行随意的映射转换,比如将水果名改成小写或者只取水果名的首字母,甚至是转换成单词长度的集合,只需在Lambda表达式中编写相应的逻辑即可。

2.3、filter函数

filter函数是用来过滤集合中的数据的,它可以单独使用也可以配合map函数来使用。比如我们只想保留5个字母以内的水果,就可以借助filter函数来完成,代码如下:

val list = listOf("apple", "orange", "watermelon", "banana")

val newList = list.filter { it.length <=5 }

.map { it.toUpperCase() }

for (fruit in newList) {

println(fruit)

}

另外值得一提的是,上述代码中我们先调用了filter函数再调用了map函数,如果改变调用的顺序,效果一样但是效率会低很多,其实很简单,因为这相当于对集合中所有元素都映射改变之后再过滤,肯定比只映射变换过滤后的效率低。

2.4、all和any函数

1、any:判断集合中至少一个元素满足指定条件

2、all:判断集合中所有元素是否都满足指定条件

val list = listOf("apple", "orange", "watermelon", "banana")

val anyResult = list.any { it.length <= 5 } //返回true

val allResult = list.all { it.length <= 5 } //返回false

println("anyResult is "+anyResult+" allResult is "+allResult)

3、Java函数式API的使用

在Kotlin中调用Java方法时也可以使用函数式API,只不过这是有一定的条件限制的,如果我们在Kotlin中调用Java方法,那么这个方法接收一个Java单抽象方法接口参数时就可以使用函数式API。Java的单抽象方法接口指的是,接口中只有一个待实现的方法。比如我们常用的接口Runnable。

public interface Runnable {

void run();

}

根据前面的讲解,对于任何一个Java方法只要它接收Runnable参数,就可以使用函数式API。比如我们在创建线程时就需要传入Runnable参数。

new Thread(new Runnable() {

@Override

public void run() {

System.out.println("子线程运行");

}

}).start();

注意这里使用了匿名类的写法,我们创建了一个Runnable接口的匿名类然后作为参数传递给Thread的构造函数。那么用Kotlin如何实现呢?

Thread(object :Runnable{

override fun run() {

println("子线程运行")

}

}).start()

Kotlin的匿名类的创建和Java有点区别,Kotlin中使用object创建匿名类实例。但是别忘了,Thread的构造方法是符合Java函数式API的使用条件的,下面看下如何精简。

1、精简待实现方法

Thread(Runnable {

println("子线程运行")

}).start()

这段代码明显精简很多,但也不会造成歧义,因为Runnable接口中只有一个待实现的方法,所以即使没有重写run()方法,Kotlin也能自动明白Runnable后面的Lambda表达式就是run()方法中实现的内容。

- 2、精简接口

如果Java方法的参数列表中只存在一个的Java单抽象方法接口参数,我们还可以对接口名进行省略。

Thread({

println("子线程运行")

}).start()

3、精简括号

和Kotlin函数式API一样,如果Lambda表达式是最后一个参数的话,可以将Lambda表达式一道小括号外面,并且如果只有这一个参数的话,可以省略小括号。

Thread{

println("子线程运行")

}.start()

再举个我们在Android中常用的点击事件的接口View.OnclikListener,定义一个button的点击事件如下:

button.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

}

});

下面我们根据我们上面的分析,再次简化一下:

button.setOnClickListener(object: View.OnClickListener{

override fun onClick(v: View?) {

println("button is clicked")

}

})

//1、简化方法

button.setOnClickListener(View.OnClickListener{

println("button is clicked")

})

//2、简化接口

button.setOnClickListener({

println("button is clicked")

})

//3、简化括号

button.setOnClickListener{

println("button is clicked")

}

最后提醒一句:本小节学习的Java函数式API的调用只限定于从Kotlin中调用Java方法,并且单独抽象方法接口必须是Java语言定义的。这么定义的原因是因为:Kotlin中有专门的高阶函数来实现更加强大的自定义函数式API功能,从而不需要像Java这样借助单抽象方法接口来实现。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值