Kotlin学习(四):kotlin函数的高级应用,android开发基础学习

本文详细介绍了Kotlin中的run,also,apply和use函数,以及它们在集合操作(如forEach,filter,map,flatMap,sum,reduce,fold)中的使用。此外,还讨论了Kotlin与Java在SAM转换上的对比,提醒在实际编程中注意事项。
摘要由CSDN通过智能技术生成

public inline fun <T, R> T.run(block: T.() -> R): R {

contract {

callsInPlace(block, InvocationKind.EXACTLY_ONCE)

}

return block()

}

接收的block类型为T.() -> Unit 所以 block里面可使用this指代调用者

run : block里面可使用this指代调用者,并且返回block的返回值

简单使用实例如下所示:

val strLenght = arrayOf(“hello”, “world”).run {

this.joinToString(" ") { s: String ->

“$s length: ${s.length}”

}

}

println(strLenght)

//输出

hello length: 5 world length: 5

3.also


also源码如下所示:

public inline fun T.also(block: (T) -> Unit): T {

contract {

callsInPlace(block, InvocationKind.EXACTLY_ONCE)

}

block(this)

return this

}

和let的区别就是返回类型不一样了,block是无返回类型,整个函数返回调用者T

核心函数 block(this) return this

简单使用实例如下所示:

val arrayStr = arrayOf(“hello”, “world”).also {

val joinToString = it.joinToString(" ") { s: String ->

“$s length: ${s.length}”

}

println(joinToString)

}

println(arrayStr is Array)

//输出

hello length: 5 world length: 5

true

4.apply


apply源码如下所示:

public inline fun T.apply(block: T.() -> Unit): T {

contract {

callsInPlace(block, InvocationKind.EXACTLY_ONCE)

}

block()

return this

}

和run的区别就是返回类型不一样了,block是无返回类型,整个函数返回调用者T

核心函数 block() return this

简单使用实例如下所示:

val arrayStr = arrayOf(“hello”, “world”).apply{

val joinToString = it.joinToString(" ") { s: String ->

“$s length: ${s.length}”

}

println(joinToString)

}

println(arrayStr is Array)

//输出

hello length: 5 world length: 5

true

5.use


use源码如下所示:

public inline fun <T : Closeable?, R> T.use(block: (T) -> R): R {

contract {

callsInPlace(block, InvocationKind.EXACTLY_ONCE)

}

var exception: Throwable? = null

try {

return block(this)

} catch (e: Throwable) {

exception = e

throw e

} finally {

when {

apiVersionIsAtLeast(1, 1, 0) -> this.closeFinally(exception)

this == null -> {}

exception == null -> close()

else ->

try {

close()

} catch (closeException: Throwable) {

// cause.addSuppressed(closeException) // ignored here

}

}

}

}

核心代码就是try catch那一块,很明显,使用use函数自动帮我们处理了,异常以及资源的关闭。所以使用Closeable相关操作的时候,推荐使用use来进行资源管理

简单使用实例如下所示:

val datas = LinkedList<Pair<Char, Int>>()

File(“build.gradle.kts”).inputStream().reader().buffered().use {

var strLine = it.readLine()

while (strLine != “”) {

strLine.groupBy { char ->

char

}.map { map ->

map.key to map.value.size

}.run {

datas.addAll(this)

}

strLine = it.readLine()

}

}

println(datas.joinToString())

//输出

(p, 1), (l, 1), (u, 1), (g, 1), (i, 1), (n, 1), (s, 1), ( , 1), ({, 1), (/, 2), ( , 5), (i, 1), (d, 1), (‘, 2), (j, 1), (a, 2), (v, 1), (/, 2), ( , 7), (i, 4), (d, 1), (’, 4), (o, 3), (r, 3), (g, 1), (., 5), (j, 2), (e, 2), (t, 2), …展示内容有限,就不全部粘贴过来了

四、kotlin集合序列变换forEach、filter、map、flatmap、sum、reduce、fold

===========================================================================================================================

1.forEach函数


forEach,熟悉java的朋友相信都不陌生,且本系列文章在之前也多次用到forEach,下面我们就看看forEach具体是怎么操作的吧

forEach源码如下所示:

public inline fun Array.forEach(action: (T) -> Unit): Unit {

for (element in this) action(element)

}

很简单是不是,就是对集合元素进行了循环处理,调用了传进来的block

那按照惯例,也提供一个小demo

arrayOf(1,2,3,4).forEach {

print(it)

}

//输出

1234

2.集合映射操作相关filter、map、flatMap


filter,保留满足条件的元素

源码如下所示:

public inline fun Array.filter(predicate: (T) -> Boolean): List {

return filterTo(ArrayList(), predicate)

}

public inline fun <T, C : MutableCollection> Array.filterTo(destination: C, predicate: (T) -> Boolean): C {

for (element in this) if (predicate(element)) destination.add(element)

return destination

}

正所谓,知其然也要知其所以然。如上源码所示,filter的本质就是,循环判断block是否满足条件,如果满足则添加进入list,最后返回

简单使用如下:

arrayOf(1,2,3,4,5,6).filter {

it>3

}.joinToString ().let {

println(it)

}

//输出

4, 5, 6

map,集合中所有的元素一一映射到其他的元素构成新的集合

源码如下所示:

public inline fun <T, R> Array.map(transform: (T) -> R): List {

return mapTo(ArrayList(size), transform)

}

public inline fun <T, R, C : MutableCollection> Array.mapTo(destination: C, transform: (T) -> R): C {

for (item in this)

destination.add(transform(item))

return destination

}

分析发现,其实本质就是创建一个新的集合,加入传入map的函数的返回值而已

简单使用如下:

arrayOf(1,2,3,4,5,6).map {

“$it hello”

}.joinToString().let {

println(it)

}

//输出

1 hello, 2 hello, 3 hello, 4 hello, 5 hello, 6 hello

flatMap,集合中所有的元素一一映射到新集合并合并这些集合得到新集合

源码如下所示:

public inline fun <T, R> Array.flatMap(transform: (T) -> Iterable): List {

return flatMapTo(ArrayList(), transform)

}

public inline fun <T, R, C : MutableCollection> Array.flatMapTo(destination: C, transform: (T) -> Iterable): C {

for (element in this) {

val list = transform(element)

destination.addAll(list)

}

return destination

}

好多同学可能都对flatMap所要表达的意思,感到困惑难以理解,但是我们仔细分析一波源码,弄懂原理就简单很多了。

首先可以看到flatMap也是创建了新的ArrayList集合并且将函数重新传入到了flatMapTo的这个函数里了,这个时候我们注意,我们传入的函数的返回类型必须是可迭代的(Iterable类型)。

那我们在看flatMapTo干了什么事情,先是循环调用者的集合,然后调用函数,拿到我们传入的函数返回的集合,最后在addAll到信创建的ArrayList返回。

这么一说是不是就好理解flatMap的映射关系了,下面我们可以看一个demo

Demo如下所示:

arrayOf(1,2,3,4,5,6).flatMap {

val arrayList = ArrayList()

arrayList.add(it)

arrayList.add(1111)

arrayList

}.joinToString().let {

println(it)

}

//输出

1, 1111, 2, 1111, 3, 1111, 4, 1111, 5, 1111, 6, 1111

3.集合的聚合操作说明sum、reduce、fold


sum,所有元素求和

源码如下所示:

public fun Array.sum(): Int {

var sum: Int = 0

for (element in this) {

sum += element

}

return sum

}

较为简单,就不做说明了。

Demo所示如下:

println(arrayOf(1,2,3,4,5,6).sum())

//输出

21

reduce,将元素依次按规则聚合,结果与元素类型一致

源码如下所示:

public inline fun <S, T : S> Array.reduce(operation: (acc: S, T) -> S): S {

if (isEmpty())

throw UnsupportedOperationException(“Empty array can’t be reduced.”)

var accumulator: S = this[0]

for (index in 1…lastIndex) {

accumulator = operation(accumulator, this[index])

}

return accumulator

}

这个也比较好理解,但需要注意几点

1.外部调用的lambda表达式会循环被调用,因为reduce内部的循环

2.传入lambda的两个参数第一个acc代表的是,上一次被调用之后的计算的最新的值,T则代表当前需要的调用者集合的值。

简单使用Demo所示如下:

val value = arrayOf(1, 2, 3, 4, 5, 6).reduce { acc, i ->

acc + i * i

}

println(value)

//输出

91

fold,给定初始值,将元素依次按规则聚合,结果与元素类型一致

源码如下所示:

public inline fun <T, R> Array.fold(initial: R, operation: (acc: R, T) -> R): R {

var accumulator = initial

for (element in this) accumulator = operation(accumulator, element)

return accumulator

}

可以看得出,fold与reduce唯一的区别就是,fold的初始值需要手动传入,而reduce的初始值拿的是集合的第一个元素

简单使用Demo所示如下:

val value = arrayOf(1, 2, 3, 4, 5, 6).fold(10) { acc, i ->

acc + i * i

}

println(value)

//输出

101

五、kotlin与java的SAM(Sinigle Abstract Method)转换对比

=================================================================================================================

1.java与kotlin转换条件对比


java:一个参数类型为只有一个方法的接口的方法调用时可用Lambda表达式做转换作为参数

kotlin:一个参数类型为只有一个方法的java接口的java方法调用时可用Lambda表达式做转换作为参数

对比例子代码如下所示:

//java正常调用

new Thread(new Runnable() {

@Override

public void run() {

System.out.println(“thread”);

}

}).start();

//java sam转换使用lambda调用

new Thread(

() -> System.out.println(“thread”)

).start();

//kotlin 正常调用

Thread(object :Runnable{

override fun run() {

println(“thread”)

}

}).start()

//kotlin sam转换调用lambda

Thread {

println(“thread”)

}.start()

java的大家都比较熟悉了,我们看一下kotlin的转换是怎么操作的吧

在这里插入图片描述

实际上相当于时编译器帮我们new了一个runable对象,并且里面调用了我们的匿名函数

2.kotlin使用SAM转换注意点


正因为编译器帮我们创建了对应的对象,所以:添加移除事件时或者涉及到同一个对象操作时,调用java的接口需要注意,直接将对应接口对象new出来,避免进行SAM转换,否则操作的就不是同一个对象!!!

在这里插入图片描述

总结

=====================================================================

以上就是本次更新的kotlin相关的知识点了,大家都学废了吗?

最后放一个小demo,加强一下动手的能力

统计字符个数

fun main() {

val linkedList = LinkedList<Pair<Char, Int>>()

// 使用 readerBuffer 可以一行一行读取数据

File(“build.gradle”).inputStream().reader().buffered()

.use {

var str = it.readLine()

while (!(“” == str)) {

str.toCharArray()

.groupBy { it }

.map {

// 映射为pair类型

it.key to it.value.size

}.let {

linkedList.addAll(it)

}

str = it.readLine()

}

}

linkedList.forEach {

println(it)

}

// 也可以使用file的扩展方法将文件内容全部读取出来 isWhitespace() 判断不是空字符

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

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

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

最后

在这里我和身边一些朋友特意整理了一份快速进阶为Android高级工程师的系统且全面的学习资料。涵盖了Android初级——Android高级架构师进阶必备的一些学习技能。

附上:我们之前因为秋招收集的二十套一二线互联网公司Android面试真题(含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。**

[外链图片转存中…(img-9Pk1Ygev-1712779975964)]

[外链图片转存中…(img-7nw3LsPG-1712779975964)]

[外链图片转存中…(img-kIbkSPGl-1712779975964)]

[外链图片转存中…(img-rFnPD9RF-1712779975965)]

[外链图片转存中…(img-6UIRt9m8-1712779975965)]

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

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

最后

在这里我和身边一些朋友特意整理了一份快速进阶为Android高级工程师的系统且全面的学习资料。涵盖了Android初级——Android高级架构师进阶必备的一些学习技能。

附上:我们之前因为秋招收集的二十套一二线互联网公司Android面试真题(含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)
[外链图片转存中…(img-Z52yNEEN-1712779975965)]

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

  • 22
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值