6.1、⾼阶函数
定义
参数包含函数类型或者返回值为函数类型。
例⼦
// 参数param是函数类型
fun test1(param: () -> Int) {
// 涉及函数的调⽤
// param()
param.invoke()
}
// 返回值是函数类型
fun test2(): () -> Int {
// 返回的是⼀个匿名函数,返回值是1
return { 1 }
}
// 定义⼀个数组
var arr = intArrayOf(1, 2, 3, 4)
// 遍历功能
arr.forEach {
Log.e(TAG, it.toString())
}
Log.e(TAG, arr.joinToString())
// 遍历,然后转成另外的元素,然后存到数组中
val map = arr.map {
it * it
}
Log.e(TAG, map.joinToString())
⾼阶函数的调⽤
// 定义⼀个数组
var arr = intArrayOf(1, 2, 3, 4)
// ⾼阶函数的引⽤ ::println表⽰对函数的引⽤
arr.forEach(::println)
⾼阶函数调⽤-简化的⼏个阶段
⾮常关键
// 定义⼀个数组
var arr = intArrayOf(1, 2, 3, 4)
// 第⼀种⽅式
arr.forEach({
println("Hello $it")
})
// 如果接受的⾼阶函数是最后⼀个参数,⼩括号可以移动到外⾯
arr.forEach() {
println("Hello $it")
}
// 如果括号中没有任何的参数,那么可以将⼩括号省略
arr.forEach {
println("Hello $it")
}
⾼阶函数应⽤ - 计算⽅法的时间
// ⾸先传⼊⼀个匿名函数
// const({
// (1..10000000).forEach { it * it }
// })
// 优化成下⾯的样式
// const(){
// (1..10000000).forEach { it * it }
// }
// 继续优化
const {
(1..10000000).forEach { it * it }
}
6.2、内联函数
定义
减少了函数的调⽤,性能优化。
具体看下⾯的分析:
我们可以看到Array.kt⽂件中forEach的定义,⾥⾯有⼀个关键字inline,它有什么作⽤呢?
public inline fun IntArray.forEach(action: (Int) -> Unit): Unit {
for (element in this) action(element)
}
我们在代码中调⽤格式如下:
// 定义⼀个数组
var arr = intArrayOf(1, 2, 3, 4)
// 第⼀种⽅式
arr.forEach({
println("Hello $it")
})
编译器最终转换为的是⼀个内联函数。
// 定义⼀个数组
var arr = intArrayOf(1, 2, 3, 4)
// 第⼀种⽅式
for(element in arr){
println(element.toString())
}
内联函数的优点
减少了函数的调⽤,性能更好。
⾼阶函数与内联函数更加匹配
⽐如下⾯的函数
class MainActivity2 : AppCompatActivity() {
val TAG = "cdx"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main2)
const({
print("1")
})
}
fun const(block: () -> Unit) {
var start = System.currentTimeMillis()
block()
var end = System.currentTimeMillis()
Log.e(TAG, (end - start).toString())
}
}
然后我们查看下编译后的代码(输⼊Show Kotlin Bytecode)
我们看下其中2个消耗时间的地⽅
1、调⽤了const⽅法。
2、创建了⼀个匿名函数。
然后我们优化const⽅法的定义,增加inline关键字,让他变成⼀个内联函数。
inline fun const(block: () -> Unit) {
var start = System.currentTimeMillis()
block()
var end = System.currentTimeMillis()
Log.e(TAG, (end - start).toString())
}
然后我们查看下编译后的代码(输⼊Show Kotlin Bytecode)
我们可以看到,省去了函数的调⽤,性能更⾼。
内联函数return(类似于continue)
这个地⽅增加return,导致forEach下⾯的语句都不执⾏
// 定义⼀个数组
var arr = intArrayOf(1, 2, 3, 4)
// 第⼀种⽅式
arr.forEach {
// 这个地⽅相当于是break
if (it == 3) return
Log.e(TAG, it.toString())
}
这个地⽅类似于continue
// 定义⼀个数组
var arr = intArrayOf(1, 2, 3, 4)
arr.forEach {
// 这个地⽅相当于是continue
if (it == 3) return@forEach
Log.e(TAG, it.toString())
}
内联属性
属性的getter和setter可以被内联,只需要在getter和setter上增加inline
class MainActivity2 : AppCompatActivity() {
val TAG = "cdx"
var pocket: Double = 0.0
// 内联属性
var money: Double
inline get() = pocket
inline set(value) {
pocket = value
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main2)
money = 5.0
}
}
然后我们编译下
发现money属性已经没有了,money属性已经被替换了。
6.3、⼏个有⽤的⾼阶函数
let、run
let:当我们需要定义⼀个变量在特定的作⽤域内,let函数是⼀个不错的选择。
// 定义对象
var person = Person("张三", 25)
val name = person.let {
it.name
}
Log.e(TAG, name.toString())
run:和let的作⽤相似,只是⼀个是it,⼀个是this
// 定义对象
var person = Person("张三", 25)
var result = person.run {
this.age
}
Log.e(TAG, result.toString())
also、apply
// 定义对象
var person = Person("张三", 25)
// 利⽤also来修改对象属性
var person2 = person.also {
it.name = it.name + "V2"
}
Log.e(TAG, person2.toString())
var person3 = person.apply {
name = "xxx"
}
Log.e(TAG, person3.toString())
6.4、集合变换与序列
filter操作
筛选出来合适的,然后放到集合中
val list = intArrayOf(1, 2, 3, 4)
// 取出偶数的值,过滤
val result = list.filter { it % 2 == 0 }
Log.e(TAG, result.toString()) // [2, 4]
map操作
遍历数组,然后进⾏操作,然后放到集合中
val list = intArrayOf(1, 2, 3, 4)
val result = list.map { it * 2 }
Log.e(TAG, result.joinToString())
flatMap操作
flatMap操作的流程图
1)⾸先取出来元素。
2)然后根据元素⽣成数组。
3)然后在将这些数组进⾏拼接。
val list = intArrayOf(1, 2, 3, 4)
val result = list.flatMap { 0 until it }
Log.e(TAG, result.joinToString()) // 0, 0, 1, 0, 1, 2, 0, 1, 2, 3
fold(折叠)操作
有⼀个初始化的值 + 拼接的规则
val list = intArrayOf(1, 4, 7)
// 初始化的值为StringBuilder()
// acc为拼接的值
list.fold(StringBuilder()) { acc, i ->
Log.e(TAG, "acc=$acc")
Log.e(TAG, i.toString())
acc.append(i)
}
懒序列懒在哪⾥?
通过调⽤asSequence(),然后只有调⽤forEach⽅法(fold、ruduce、sum)以后, 才会去执⾏上⾯的filter、map、flatMap⽅法。
6.5、SAM(单⼀抽象⽅法转换)转换
SAM转换例⼦
如果只有⼀个⽅法,那么这个匿名内部类可以⾮常的简化,只有⼀个{ } 。
// SAM例⼦
var exe: ExecutorService? = null
// 匿名内部类
// exe?.submit(object : Runnable {
// override fun run() {
// Log.e(TAG,"任务执⾏的")
// }
// })
// 简化写法
// exe?.submit({
// Log.e(TAG, "任务执⾏的")
// })
// 继续简化
exe?.submit {
Log.e(TAG, "任务执⾏的")
}
kotlin的匿名内部类
// 匿名内部类的通常写法
object : Runnable {
override fun run() {
Log.e(TAG,"任务执⾏的")
}
}
// 匿名内部类的简写写法
Runnable {
Log.e(TAG,"任务执⾏的")
}