Kotlin高阶函数、内联函数以及集合变换序列_fun a() () -> unit(1)

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!


img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上鸿蒙开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

需要这份系统化的资料的朋友,可以戳这里获取

inline fun inlineFun(block:() -> Unit){
val curTime = System.currentTimeMillis()
block()
println(System.currentTimeMillis() - curTime)
}

//这个时候再调用
inlineFun{
println(“Kotlin”)
}

//其实际执行的是
val curTime = System.currentTimeMillis()
println(“Kotlin”)
println(System.currentTimeMillis() - curTime)


这样编译时创建lamba表达式匿名类开销就没了,所以内联函数的原理是:**Kotlin在编译时会把内联函数内代码搬到要调用的地方,** 就好像我们写了这段代码一样。


**内联函数的noinline和crossinline**


一个高阶函数如果被`inline`关键字修饰,那么它接收的所有函数类型的参数均会被内联,如果想某个函数类型的参数不被内联,就需要用关键字`noinline`修饰。


那这就有一个问题:既然前面我们说内联函数能消除Lambda表达式运行时带来的额外内存开销,那么为啥还提供了一个`noinline`来排除内联呢?


**这里主要是因为内联函数类型的参数只能传递给内联函数,而非内联则可以传递给任何函数,另外不同的一点是内联函数可以返回外部函数,就是调用该内联函数的函数,而非内联函数则返回局部。**


下面代码看看内联函数的返回和非内联函数的返回:



inline fun nonLocalReturn(block:() -> Unit){
block()
}

fun main(){

println("main start")
nonLocalReturn{
    println("lambda start")
    //这里return 就是直接返回到main函数了
    return
    println("lambda end")
}
println("main end")

}
//执行打印的结果是
main start
lambda start
说明直接返回到main函数了,没有再往下执行

//如果我们没有定义成内联函数
fun nonLocalReturn(block:() -> Unit){
block()
}

fun main(){
println(“main start”)
nonLocalReturn{
println(“lambda start”)
return@nonLocalReturn
println(“lambda end”)
}
println(“main end”)
}

//这里打印的结果是
main start
lambda start
main end
说明仅仅是返回了nonLocalReturn函数,main函数还是往下走了


**crossinline关键字**


绝大多数高阶函数都可以声明为内联函数,但是也有例外的情况。如下列代码:



inline fun Runnable(block:() -> Unit):Runnable{
return object:Runnbale {
override fun run(){
block()
}
}
}


这个时候idea会提示block()调用错误,这是因为有可能存在不合法的non-local return,block()的调用处与定义处不在一个调用上下文。


那么如何解决这个问呢?


使用crossinline关键字修饰传递的函数就可以使它在Lambda表达式中一定不return,而且`crossinline`修饰除了不return之外,其他内联函数的属性都是一样的。


**三、几个常用的高阶函数**


**let函数**


let函数调用一般是针对一个定义在特定情况下使用的变量,例如我们可以避免对变量的null判断。观察如下代码:



// any 不为null 时才会调用let 函数
any?.let {
//it 就是代表any对象
// todo()方法就是any对象的方法
// it.todo()的返回值作为let函数的返回值返回
it.todo()
}


在Android开发中的实际场景就是我们可能要对一个变量进行多次判空才调用,如:



mTextView?.text = “Kotlin”
mTextView?.textSize = 16f


使用let函数后可以简写为



mTextView?.let{
it.text = “Kotlin”
it.textSize = 16f
}


**run函数**


run函数其实就是let函数的升级版,run函数接受一个lambda 函数为参数,传入this并以闭包形式返回,返回值是最后的计算结果,那么上述的代码可以优化成下面这样:



mTextView?.run{
text = “Kotlin”
textSize = 16f
}


**apply函数**


apply函数和run函数的结构模式很相像,但是apply函数返回的是调用对象本身,因为apply函数的这个特性,所以它特别有助于我们进行多级的判null行为。下面我们通过一个代码示例了解一下:


apply函数的一般结构:



val applyRes = any.apply{
//todo()是 any 对象的共有属性或方法
todo()
// 最后返回的是any对象,而不是2
1+1
}


apply的简单应用举例:



//定义了一个公司对象 包含部门和人员名字
class Company(var department:Department? = null){
class Department(var departmentName: String? = null,var person:Person? = null){
class Person(var name:String? = null)
}
}

fun main() {
val company:Company? = Company(Company.Department(“一部”, Company.Department.Person(“Jeremy”)))
company?.department?.apply {
departmentName = “二部”
}?.person?.name.also {
println(“这个 c o m p a n y ? . d e p a r t m e n t ? . d e p a r t m e n t N a m e 的员工是 {company?.department?.departmentName}的员工是 company?.department?.departmentName的员工是it”)
}
}

打印的信息是:这个二部的员工是Jeremy


**also函数**


上述的apply应用举例中,我们最后调用了also函数,这个函数的作用和let函数是类似的,其中it就是返回的调用对象本身,其一般的结构格式就是:



val alsoRes = any.also {
//it代表的就是any todo是any的属性方法
it.todo()
1+1 //返回的是any对象,而不是2
}


**use函数**


use函数最大的一个特征就是会自动关闭调用者,无论其中间是否出现异常,因为use函数内部实现也是通过try-catch-finally块捕捉的方式,而close操作在finally里面执行,所以无论是正常结束还是出现异常,都能正确关闭调用者。


怎么才能调用use函数呢?


凡是实现了Closeable接口的对象都可以调用use函数。


因为use函数使得Kotlin中对File对象和IO流操作变得行云流水。



File(“build.gradle”).inputStream().reader().buffered()
.use {
print(it.readLines())


**四、集合变换序列**


**4.1、filter操作**


filter的操作是保留满足条件的元素得到新的列表,观察下列代码:



val arr = intArrayOf(1,2,3,4)
//asSequence()转换成懒序列
val arrFilter = arr.asSequence().filter { it%2 == 0 }
val arrFilter = arr.filter { it%2 == 0 }

for (e in arrFilter){
println(e)
}

打印的数据:
2
4


**4.2、map变换**


map变换就是一种映射一一对应的操作:



val list: MutableList = mutableListOf(1, 2, 3, 4)
val listMap = list.map { it*2 + 1}
for (e in listMap){
println(e)
}

打印的数据是:
3
5
7
9

集合的每个数据对应执行lamba表达式中的it*2 + 1返回一个新的数据集合


下面我们看一下filter和map结合的使用


懒序列调用法:



val list: MutableList = mutableListOf(1, 2, 3, 4)
list.asSequence().filter {
println(“filter $it”)
it % 2 ==0
}.map {
println(“map $it”)
it*2 + 1
}.forEach {
println(“forEach $it”)
}

打印结果:
filter 1
filter 2
map 2
forEach 5
filter 3
filter 4
map 4
forEach 9


上述看到打印结果是主要有符合条件的都会先往下走,**懒序列有一个很重要的点就是forEach是一个阀门作用,如果把forEach去掉就不会执行前面filter和map的操作,这就是懒序列的意义,当你需要的时候才会执行**。那我们看一下饿汉式的调用结果:



val list: MutableList = mutableListOf(1, 2, 3, 4)
list.filter {
println(“filter $it”)
it % 2 ==0
}.map {
println(“map $it”)
it*2 + 1
}.forEach {
println(“forEach $it”)
}

打印结果:

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

Each {
println(“forEach $it”)
}

打印结果:

[外链图片转存中…(img-vV8unKww-1715895501717)]
[外链图片转存中…(img-Bf74qZZd-1715895501717)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值