一文弄懂 kotlin lambda与高阶函数

3,491 阅读5分钟

阅读本文能解决什么问题

我发现很多学过kotlin的人,迟迟不敢在项目中运用,主要是因为kotlin的 lambda与高阶函数没有学好。这2个东西往往是一起运用的。 网上很多类似的文章都讲的不够通透,导致大部分人都卡在这里。或者有一些人即使写了kotlin 但是也没用好lambda与高阶函数,导致kotlin的代码 全是java的味道。

大家可以用一下新版本的android studio,然后新建一个kotlin语言的loginActivity,如果里面的代码你能无障碍的基本看懂,那这篇文章就不用再看了,如果看起来障碍很大,那么建议你仔细看完这篇文章,之后再返回去看这个loginActivity的代码,相信结果是完全不一样的。

最后总结一下我的观点:想写好Kotlin的代码就看你对lambda与高阶函数理解的有多深,早期纠结那些晦涩的语法糖没有任何意义

到底啥是匿名函数

那这个func 又怎么理解呢?他为啥可以接受一个函数作为参数?

这里有人会问了,你咋知道 这个匿名函数是没有返回值的啊?

因为lambda表达式有一个特点,lambda括号里面的函数最后一行就是这个函数的返回值, 图中我们最后一行 是个print语句,这个print函数显然是没有返回值的,所以这个lambda 也就是这个匿名函数也就没有了返回值了。

带参数的lambda

然后我们反编译看一下这段代码

我们换个写法

我们再看一下反编译的:

下面我们再改进一下写法:

那当然还有终极的简写,也就是平常我们使用最多的写法:

很多人学不好lambda就是因为上来就看这个最简单的写法,而不知道这种写法是怎么来的。你搞清楚 这种写法的进化原因,自然就真正理解了lambda了。

来个更进一步 2个参数的

看下执行结果

实际上kotlin中的lambda 就是一个匿名函数,java8的lambda表达式 却是一个sam的语法糖

高阶函数

有了前面lambda 的铺垫,高阶函数 的理解就不难了。 下面给高阶函数下一个定义: 参数类型包含函数类型,或者返回值类型是一个函数类型 的函数 都可以称之为是高阶函数。

来看几个简单的高阶函数的例子:

看下源码:

再看个函数

然后我们看一下map函数的定义

所以你看高阶函数 也没什么难的,主要你能理解lambda 那么你就能理解好高阶函数

谷歌源码里最常用的几个高阶函数

无非就是let run also apply use 这么5个,网上关于这几个函数的资料很多,但是介绍的我觉得都相当一般,这里我重新介绍一下 这几个函数对应的使用场景。 掌握了他们,可以说 理解kotlin的代码 就不会存在什么障碍了。

这里要着重说明的是,其实run函数和apply函数 并没啥大作用。平时自己写 主要还是let also 和use

看一段代码,看看let和also的区别

最后一个use操作符,是个人最爱的一个操作符,因为这东西真的省事。我演示一遍你就知道他有多省事了!

最后用一张图来总结:

高阶函数-集合的变换

我们平时开发业务代码时 其实最主要的工作就是对一个集合进行增删改查,过滤啊 之类的操作。 kotlin中 提供了大量对集合操作的 高阶函数,理解好他们 对你读代码或者是写代码的操作都是非常非常有帮助的。

前面的代码中我们已经演示过了for each循环的用法 这里补充一点,foreach函数是可以提前跳出的。

当然上面的写法一般是不推荐的,因为确实很迷惑人。 有更高级的函数 可以满足你对集合的要求。

看下图:

看个例子:

有时候我们对一个集合的操作,可能不止一个函数,需要多个函数协同操作,这个时候有更方便的 写法。

有人要问了,这个asSeq不调用 是啥效果?我们可以看一下

再看一个例子

看下flatmap

集合的聚合操作

先看一张图 了解一下主要的聚合操作

看下fold的使用

其余的2个高阶函数就不再演示了。大家用到的时候自行查阅api即可。

试试高阶函数和lambda 怎么组合使用 解决问题?

前面已经学完了lambda和大部分高阶函数,这里我们组合一下他们的用法,重新将知识串起来。

1.统计一个文件里 除了空格字符以外,每个字符出现的次数(尽量只使用lambda)

/**
 *  1.读文件 然后把文件的内容 转成char的数组
 *  2.过滤数组,空格符直接忽略
 *  3.用groupBy 来将整个数组 重新分组(分组的结果是一个map), key就是出现的字符,value就是出现的全部字符
 *  4.用map操作符 再将这个map 拍平成一个list,这个list的 内容形如:e 出现次数: 21
 *  5.用let操作符 将结果打印出来即可
 */
fun main() {

    File("/Users/wuyue/IdeaProjects/KotlinTest/src/enumTest.kt").readText().toCharArray().filterNot {
        it.isWhitespace()
    }.groupBy {
        it
    }.map {
        it.key + " 出现次数: " + it.value.size
    }.let {
        println(it)
    }
}