概念:
一切皆可视为函数。与面向对象(OOP),‘一切皆对象’ 相对应 ‘一切皆函数’也是函数式编程的含义。包括经常被形象成为,函数在Kotlin中是一等公民,这句话也是相对OOP编程范式中,方法必须依托类或对象才能存在。对象可以被传递,函数也可以被传递,对象可以作为返回值,函数也可以作为返回值。
如何理解Lambda expression
个人理解为,代数方程,函数的输入和输出明确后,方程式就已经定好 y = n * m,对于输入为类型为n, m,返回值为y类型的函数,都可以转换为相同的函数签名,数学上叫‘泛函数’, 即lambda。lambda简化了函数的定义。
为什么要称为‘高阶’函数
wiki上定义为,接受一个或多个函数作为输入,或输出一个函数。所以“高”对应的“低”,是指不符合这两个条件,也就是一阶函数(first-order function),不依赖其他函数,有直接返回值(类似递归基)。所以“高阶”对应了函数映射到另一个“低阶”函数,最终求解。
如何理解懒加载
需要计算,才计算其中内容,声明函数,传递函数,不会导致函数执行
高阶函数实例
fun twice(f: (Int) -> Int): (Int) -> Int = { x ->
f(f(x))
}
val plusTwo = twice { it + 1 }
val plusTwo = twice { it::inc //函数式 }
println(plusTwo.invoke(2))
println(twice { it + 1 }.invoke(2))
一些作用域高阶函数
getUserName()?.let {
// it, 无返回值,空安全
}
val name = getUserName().apply {
// this, 返回自身,用于同一个对象多次调用
}
val name = with(getUserName()) {
// this, 返回最后一行,用于泛对象多次调用
"Hello"
}
val name = getUserName()?.run {
// this, 返回最后一行, 空安全,常用于缩小变量作用域
"Hello"
}
val name = getUserName()?.also {
// it, 返回自身,空安全,用于日志,拦截
}
// Closeable 使用后释放
val name = File("book.txt")
.bufferedReader()
.use { it.readLine() }
// Closeable 使用后释放
val name = File("book.txt")
.useLines {
println(it)
}
带接收者的Lambdas
上面apply和let两个高阶函数的差异为
public inline fun <T, R> T.let(block: (T) -> R): R
public inline fun <T> T.apply(block: T.() -> kotlin.Unit): T
T.() -> kotlin.Unit被称为带接收者的lambda,可以理解为扩展方法类似的实现,将输入It,替换为this.
Lazy 懒加载
public fun <T> lazy(initializer: () -> T): kotlin.Lazy<T>
val name by lazy {
"Brook"
}
val friends = sequenceOf("Lucy, Eric, Tom")
val nums = (1..1000).asSequence()
By lazy 将实现委托,返回了kotlin.Lazy,当调用到的时候,才会真正的调用initializer: () -> T,实现大对象,延迟初始化,非必要对象不初始化,减少性能损耗。
而对于集合,连续的数据,则是通过Sequence来实现,类似于Java8的Stream,操作符分为中间操作符,如ma p, filter 和终结操作符,take, toList(), 将数据以数据流的形式发送,处理。降低大集合内存占用和不必要的数据的占用。
性能差异
普通集合类似于批处理,一次求解,大数据量复杂操作,性能提升明显。
val timeSquence = measureTimeMillis {
val nums = (1..1000000).asSequence()
.filter { (it and 1) == 1 }
.take(2)
}
println(timeSquence)
val time = measureTimeMillis {
val nums = (1..1000000)
.filter { (it and 1) == 1 }
.take(2)
}
println(time)