《Kotlin高阶函数完全指南:从入门到精通的15个核心函数》
- 引言
- 作用域函数
- 集合操作函数
- 延迟执行函数
- 判断/检查函数
- 内联函数 inline(核心重点)
引言
Kotlin 的高阶函数是其最强大的特性之一,它让代码更简洁、更具表现力。本文将基于实际代码示例,全面介绍 Kotlin 中的作用域函数、集合操作函数、延迟执行函数、判断检查函数以及内联函数,帮助你彻底掌握这些核心概念。
作用域函数
let — 空安全调用利器
let 在对象上下文中执行代码块,返回最后一行的结果,最常用于空安全调用。
/** * let:在对象上下文中执行代码块,返回最后一行结果,常用于空安全调用 */funletDemo(){valname="Kotlin"vallength=name.let{Log.d("MainActivity2",it)it.length}Log.d("MainActivity2","$length")}/** * let + 安全调用:仅在 user 不为 null 时执行 */funletDemo1(user:User?){user?.let{Log.d("MainActivity2","name:${it.name}")Log.d("MainActivity2","age:${it.age}")}}run — 使用 this 作为上下文
run 与 let 类似,但使用 this 作为上下文引用,同样返回最后一行结果。
/** * run:类似 let,但直接使用 this 作为上下文,返回最后一行结果 */funrunDemo(user:User?){valfinalStr=user?.run{valfinalData="name:${user.name}age:${user.age}"finalData}Log.d("MainActivity2","finalStr:$finalStr")}with — 非扩展函数形式
with 不是扩展函数,需要将对象作为参数传入,适用于对同一对象进行多次操作。
/** * with:非扩展函数,传入对象作为上下文,返回最后一行结果 */funwithDemo(name:String,age:Int):String{returnwith(StringBuilder()){append("姓名:")append(name)append(" ")append("年龄:")append(age)append("岁")toString()}}apply — 对象初始化神器
apply 返回对象本身,非常适合用于初始化对象属性。
/** * apply:返回对象本身,常用于初始化对象属性 */funapplyDemo():User{returnUser().apply{name="Kotlin-Apply"age=15}}also — 附加操作的好帮手
also 同样返回对象本身,常用于日志记录、调试等附加操作。
/** * also:返回对象本身,常用于附加操作如日志记录 */funalsoDemo(){valresult=User().also{Log.d("MainActivity2","开始记录")}.apply{name="Kotlin-Also"}.also{Log.d("MainActivity2","name:${it.name}")}.apply{age=15}.also{Log.d("MainActivity2","age:${it.age}")}Log.d("MainActivity2","最终的结果:$result")}集合操作函数
map — 元素类型转换
将集合中的每个元素转换为另一种类型。
/** * map:将集合中的每个元素转换为另一种类型 */funmapDemo():List<Info>{valdataList=mutableListOf<User>()valuser1=User().apply{name="Kotlin"age=15}dataList.add(user1)valuser2=User().apply{name="Android"age=16}dataList.add(user2)valmapList=dataList.map{data->Info().apply{name=data.name age=data.age}}returnmapList}filterNotNull — 过滤空值
/** * filterNotNull:过滤掉集合中的 null 元素 */funfilterDemo():List<User>{vallistData=listOf(User().apply{name="这是一个user"age=10},null)valfinalData=listData.filterNotNull()returnfinalData}forEach — 遍历集合
/** * forEach:遍历集合并执行操作 */funforEachDemo(){vallistData=listOf(1,2,3,4,5)listData.forEach{Log.d("MainActivity2","$it")}}reduce — 累积计算
/** * reduce:从第一个元素开始累积计算 */funreduceDemo():Int{// reduce: 从第一个元素开始累积valnumbers=listOf(1,2,3,4,5)valfinalData=numbers.reduce{acc,n->acc+n}returnfinalData}groupBy — 分组
/** * groupBy:按条件分组,返回 Map */fungroupByDemo():List<Int>?{valnumbers=listOf(1,2,3,4,5,6,7,8,9,10)// 按奇偶分组valgroupedByParity=numbers.groupBy{if(it%2==0)"偶数"else"奇数"}valfinalData=groupedByParity["偶数"]returnfinalData}sortedBy — 排序
/** * sortedBy:按指定规则排序 */funsortedByDemo():List<String>{valwords=listOf("Kotlin","Java","Python","Go","Rust")valbyLength=words.sortedBy{it.length}returnbyLength}延迟执行函数
lazy — 懒加载
lazy 委托属性只在首次访问时才创建对象,常用于耗时的初始化操作。
/** * lazy:延迟初始化,首次访问时才创建对象 */funlazyDemo():User{valuserInfobylazy{User()}returnuserInfo}repeat — 重复执行
/** * repeat:重复执行某段代码 n 次 */funrepeatDemo(){repeat(20){Log.d("MainActivity2","Hello Kotlin")}}判断/检查函数
any
是否存在至少一个满足条件
/** * any:是否存在至少一个元素满足条件 */funanyDemo():Boolean{valnumbers=listOf(1,2,3,4,5)valhasEven=numbers.any{it%2==0}returnhasEven}all
是否所有元素都满足条件
/** * all:是否所有元素都满足条件 */funallDemo():Boolean{valnumbers=listOf(2,4,6,8,10)valallEven=numbers.all{it%2==0}returnallEven}none
是否没有元素满足条件
/** * none:是否没有元素满足条件 */funnoneDemo():Boolean{valnumbers=listOf(1,2,3,4,5)valnoEven=numbers.none{it%2==0}returnnoEven}count
统计满足条件的元素个数
/** * count:统计满足条件的元素个数 */funcountDemo():Int{valnumbers=listOf(1,2,3,4,5,6,7,8,9,10)valevenCount=numbers.count{it%2==0}returnevenCount}firstOrNull
查找第一个满足条件的元素
/** firstOrNull:查找第一个满足条件的元素,找不到返回 null */funfindDemo():Int?{valnumbers=listOf(1,2,3,4,5,6,7,8,9,10)valsameAsFirstOrNull=numbers.firstOrNull{it%2==0}returnsameAsFirstOrNull}内联函数 inline(核心重点)
Lambda 的本质问题
普通的高阶函数在运行时,每次调用都会创建一个匿名函数对象(Lambda 对象),带来额外的内存开销和性能损耗。
// 普通高阶函数funoperateOnNumber(x:Int,operation:(Int)->Int):Int{returnoperation(x)}编译后近似等价于:
vallambda=object:Function1<Int,Int>{overridefuninvoke(x:Int):Int=x*2}valresult=operateOnNumber(5,lambda)// 每次调用都创建对象inline 解决方案
使用 inline 关键字,编译器会将函数体直接"内联"到调用处,消除 Lambda 对象的创建
inlinefunoperateOnNumber1(x:Int,operation:(Int)->Int):Int{returnoperation(x)}funinlineDemo(){valresult=operateOnNumber1(5){it*2}// 编译后代码会被内联为:val result = 5 * 2}inline 的两大好处
消除 Lambda 对象创建 — 减少内存分配和 GC 压力
支持非局部返回 — 可以在 Lambda 中直接 return 外层函数
注意:inline 虽好,但不宜滥用。对于较大的函数体,内联会导致字节码膨胀,此时可考虑使用 noinline 或 crossinline。
掌握这些高阶函数,能让你的 Kotlin 代码更加简洁、优雅、高效。建议在实际开发中有意识地使用这些函数,逐步形成函数式编程思维。