前言
开个新坑,以后会慢慢更新..
此博客将讲解高阶函数的学习使用与实际使用的例子记录.
了解高阶函数,需要了解一个关键概念: 高阶函数与lambda表达式的关系密不可分. 怎么理解这句话呢?
我们可以先可以看看普通函数与高阶函数的区别,普通函数的参数使用实例 高阶函数的参数使用lamdba表达式,如下代码中可以查看
普通函数:
这是一个String类里的普通函数, 这里我们可以看到 函数的参数是一个IntRange类实例, 返回值是一个String
public fun CharSequence.substring(range: IntRange): String = subSequence(range.start, range.endInclusive + 1).toString()
高阶函数:
这是一个String类里的高阶函数, 这里我们可以看到 函数的参数是一个lamdba表达式, 返回值是一个String
public inline fun String.filter(predicate: (Char) -> Boolean): String { return filterTo(StringBuilder(), predicate).toString() }
对比后我们可以这么理解下一个问题,将lamdba作为参数的优势是什么?
1.lamdba作为参数可以表现出很大的灵活性,允许你在里面实现代码逻辑后返回参数
2.符合人类的阅读习惯,易于阅读(前提是你不要嵌套大量的代码与大量的其他高阶函数) . 在设计良好的高阶函数上可以体验到读文本小说的方式进行阅读代码
参考 Kotlin inline, noinline and crossinline
高阶函数实践例子
根据传入集合里的时间戳字段,查找一天中最大的时间戳item,并且收集成集合返回
public inline fun <T> Iterable<T>.findTheDailyMaxTimestamp(crossinline predicate: (T) -> Long): List<T> { var currentDayTime = 0L val timestampArray = this.toMutableList() timestampArray.sortByDescending { predicate(it) } val returnList = mutableListOf<T>() for (item in timestampArray) { //这里是关键,从实体类中去得参数里指引的目标的字段 val time = predicate(item) if (currentDayTime == 0L) { currentDayTime = time returnList.add(item) continue } val currentCalendar = Calendar.getInstance() currentCalendar.timeInMillis = currentDayTime val crtYear = currentCalendar.get(Calendar.YEAR) val crtDay = currentCalendar.get(Calendar.DAY_OF_YEAR) val itemCalendar = Calendar.getInstance() itemCalendar.timeInMillis = time val itemYear = itemCalendar.get(Calendar.YEAR) val itemDay = itemCalendar.get(Calendar.DAY_OF_YEAR) if (crtYear == itemYear && crtDay == itemDay) { continue } currentDayTime = time returnList.add(item) } return returnList }
使用了 扩展函数 加 内联函数, 在一些需要查找一天里需要显示日期的数据集合使用,特别适合在下面图片中情景下使用(稍微改造还能变成按月查找)
使用:
val findList: List<FamilyBean> = mList.findTheDailyMaxTimestamp { it1 -> it1.createTime }
两个集合字段对比的函数
多参数判空例子
在kotlin多个参数的判空非常讨厌,需要多层嵌套let函数. 这里我们可以实现一个多参数判空的函数,优化这种代码
/** * 参数不等于null就执行 */ fun <T1, T2> notNullLet(obj1: T1?, obj2: T2?, let: (T1, T2) -> (Unit)) { if (obj1 != null && obj2 != null) { let(obj1, obj2) } } /** * 参数不等于null就执行 */ fun <T1, T2, T3> notNullLet(obj1: T1?, obj2: T2?, obj3: T3?, let: (T1, T2, T3) -> (Unit)) { if (obj1 != null && obj2 != null && obj3 != null) { let(obj1, obj2, obj3) } } /** * 参数不等于null就执行 */ fun <T1, T2, T3, T4> notNullLet(obj1: T1?, obj2: T2?, obj3: T3?, obj4: T4, let: (T1, T2, T3, T4) -> (Unit)) { if (obj1 != null && obj2 != null && obj3 != null && obj4 != null) { let(obj1, obj2, obj3, obj4) } }
使用:
val deviceState = mLockViewModel.deviceStateResult.value notNullLet(mLockViewModel.currentBleDeviceInfo?.functionList, deviceState, mLockViewModel.currentFamilyDevice?.deviceSn) { functionList, deviceState, deviceSn -> mCatEyeUserListViewModel.postPasswordData(deviceSn, deviceState, functionList) showLoadingDialog() }
End