Appearance
Kotlin 高阶函数详解 🎯
Android 面试必考 Kotlin 高阶函数,包含函数类型、Lambda 参数、返回函数、内联高阶函数、标准库高阶函数等核心知识点
目录
1. 函数类型
1.1 基础语法
函数类型表示可以存储和传递的函数引用:
kotlin
// 基本函数类型
val sum: (Int, Int) -> Int = { a, b -> a + b }
// 无参数函数
val greet: () -> String = { "Hello" }
// 无返回值函数
val printHello: () -> Unit = { println("Hello") }
// 可空函数类型
val optionalFunc: (() -> Unit)? = null
// 带接收者的函数类型
val block: StringBuilder.() -> Unit = {
append("Hello")
append(" World")
}1.2 函数类型的变量
kotlin
// 声明函数类型变量
var operation: (Int, Int) -> Int
// 赋值
operation = { a, b -> a + b }
operation = { a, b -> a - b }
operation = { a, b -> a * b }
// 调用
val result = operation(3, 4) // 7
// 函数类型作为属性
class Calculator {
var operation: (Int, Int) -> Int = { a, b -> a + b }
fun calculate(a: Int, b: Int): Int {
return operation(a, b)
}
}
// 使用
val calc = Calculator()
calc.calculate(3, 4) // 7
calc.operation = { a, b -> a * b }
calc.calculate(3, 4) // 121.3 函数类型的完整语法
kotlin
// 完整语法:(参数类型,...) -> 返回类型
val func1: (Int) -> Int = { x -> x * 2 }
// 多个参数
val func2: (Int, Int) -> Int = { a, b -> a + b }
// 带命名参数(调用时使用)
val func3: (a: Int, b: Int) -> Int = { a, b -> a + b }
// 可空参数和返回
val func4: (Int?) -> String? = { num -> num?.toString() }
// 带接收者的函数类型
val func5: Int.(Int) -> Int = { x -> this + x }
// 使用
val result = 5.func5(3) // 8,this 是 5
// 挂起函数类型
val suspendFunc: suspend () -> String = {
withContext(Dispatchers.IO) {
"Result from IO"
}
}1.4 函数类型与匿名函数
kotlin
// Lambda 表达式
val sum1: (Int, Int) -> Int = { a, b -> a + b }
// 匿名函数
val sum2: (Int, Int) -> Int = fun(a, b): Int {
return a + b
}
// 匿名函数可以指定返回类型
val sum3 = fun(a: Int, b: Int): Int {
return a + b
}
// 带接收者的匿名函数
val block: StringBuilder.() -> Unit = fun() {
this.append("Hello") // this 是 StringBuilder
}
// 使用
val sb = StringBuilder()
sb.block()1.5 函数类型的实际场景
kotlin
// 1. 策略模式
class DataProcessor {
var filterStrategy: (Int) -> Boolean = { true }
var transformStrategy: (Int) -> Int = { it }
fun process(data: List<Int>): List<Int> {
return data.filter(filterStrategy).map(transformStrategy)
}
}
// 使用
val processor = DataProcessor()
// 只处理偶数
processor.filterStrategy = { it % 2 == 0 }
// 加倍
processor.transformStrategy = { it * 2 }
val result = processor.process(listOf(1, 2, 3, 4, 5))
// [4, 8]
// 2. 回调函数
class Button {
var onClick: (() -> Unit)? = null
fun click() {
onClick?.invoke()
}
}
// 使用
val button = Button()
button.onClick = {
println("Button clicked!")
}
button.click()
// 3. 配置 DSL
class Dialog {
var title: String = ""
var message: String = ""
var positiveButton: String = "OK"
fun show() {
println("Dialog: $title - $message")
}
}
fun dialog(configure: Dialog.() -> Unit): Dialog {
return Dialog().apply(configure)
}
// 使用
dialog {
title = "提示"
message = "确定要删除吗?"
positiveButton = "删除"
}.show()2. 高阶函数定义
2.1 基础概念
高阶函数是接受函数作为参数或返回函数的函数:
kotlin
// 接受函数作为参数
fun operate(a: Int, b: Int, operation: (Int, Int) -> Int): Int {
return operation(a, b)
}
// 使用
val result = operate(3, 4) { a, b -> a + b } // 7
// 返回函数
fun getMultiplier(factor: Int): (Int) -> Int {
return { x -> x * factor }
}
// 使用
val double = getMultiplier(2)
println(double(5)) // 102.2 高阶函数的多种形式
kotlin
// 形式 1:单个函数参数
fun <T> List<T>.forEach(action: (T) -> Unit) {
for (element in this) {
action(element)
}
}
// 形式 2:多个函数参数
fun <T> List<T>.filterMap(
predicate: (T) -> Boolean,
transform: (T) -> String
): List<String> {
return this.filter(predicate).map(transform)
}
// 形式 3:函数参数有默认值
fun <T> List<T>.process(
filter: (T) -> Boolean = { true },
transform: (T) -> T = { it }
): List<T> {
return this.filter(filter).map(transform)
}
// 形式 4:返回函数
fun createCounter(): () -> Int {
var count = 0
return { count++ }
}
// 使用
val counter = createCounter()
println(counter()) // 0
println(counter()) // 1
println(counter()) // 22.3 尾随 Lambda 参数
当最后一个参数是函数时,可以将其放在括号外:
kotlin
// 定义
fun <T> List<T>.customMap(transform: (T) -> Int): List<Int> {
return this.map(transform)
}
// 调用 - 尾随 Lambda
val numbers = listOf(1, 2, 3)
val result = numbers.customMap {
it * 2
}
// 多个参数时
fun <T> List<T>.process(
prefix: String,
transform: (T) -> String
): List<String> {
return this.map { "$prefix${transform(it)}" }
}
// 调用
val result = numbers.process("Number: ") {
it.toString()
}2.4 高阶函数实战
kotlin
// 1. 重试机制
suspend fun <T> retry(
times: Int = 3,
delayMs: Long = 1000,
operation: suspend () -> T
): T {
var lastException: Exception? = null
repeat(times) { attempt ->
try {
return operation()
} catch (e: Exception) {
lastException = e
if (attempt < times - 1) {
delay(delayMs)
}
}
}
throw lastException ?: Exception("Unknown error")
}
// 使用
val result = retry(times = 3, delayMs = 2000) {
api.loadData()
}
// 2. 超时处理
suspend fun <T> withTimeout(
timeoutMs: Long,
block: suspend () -> T
): T {
return withTimeout(timeoutMs) {
block()
}
}
// 3. 事务处理
fun <T> transaction(
begin: () -> Unit,
commit: () -> Unit,
rollback: () -> Unit,
operation: () -> T
): T {
begin()
return try {
val result = operation()
commit()
result
} catch (e: Exception) {
rollback()
throw e
}
}
// 4. 测量执行时间
fun <T> measureTime(block: () -> T): Pair<T, Long> {
val start = System.currentTimeMillis()
val result = block()
val duration = System.currentTimeMillis() - start
return result to duration
}
// 使用
val (result, time) = measureTime {
expensiveOperation()
}
println("Result: $result, Time: ${time}ms")3. Lambda 作为参数
3.1 Lambda 语法回顾
kotlin
// 完整语法
val sum = { a: Int, b: Int -> a + b }
// 类型推断
val sum: (Int, Int) -> Int = { a, b -> a + b }
// 单个参数可以使用 it
val double: (Int) -> Int = { it * 2 }
// 无参数
val greet: () -> String = { "Hello" }
// 多行 Lambda
val complex = { x: Int, y: Int ->
val sum = x + y
val product = x * y
sum + product
}3.2 Lambda 作为参数的模式
kotlin
// 模式 1:单一 Lambda 参数
fun <T> List<T>.forEach(action: (T) -> Unit) {
for (element in this) action(element)
}
// 调用
listOf(1, 2, 3).forEach {
println(it)
}
// 模式 2:Lambda 是最后一个参数
fun <T, R> List<T>.map(transform: (T) -> R): List<R> {
return this.map(transform)
}
// 调用 - Lambda 放在括号外
val result = listOf(1, 2, 3).map {
it * 2
}
// 模式 3:多个 Lambda 参数
fun <T> List<T>.filterMap(
predicate: (T) -> Boolean,
transform: (T) -> String
): List<String> {
return this.filter(predicate).map(transform)
}
// 调用
val result = listOf(1, 2, 3, 4, 5).filterMap(
{ it % 2 == 0 },
{ "Number: $it" }
)
// 模式 4:带接收者的 Lambda
class Builder {
var name: String = ""
var age: Int = 0
}
fun build(block: Builder.() -> Unit): Builder {
return Builder().apply(block)
}
// 调用
val person = build {
name = "张三"
age = 25
}3.3 Lambda 参数的命名约定
kotlin
// 单个参数使用 it(标准库约定)
list.map { it * 2 }
// 多个参数或需要清晰语义时命名
list.map { number -> number * 2 }
list.forEachIndexed { index, value ->
println("$index: $value")
}
// 成对解构
map.forEach { (key, value) ->
println("$key: $value")
}
// 忽略不需要的参数
list.forEach { _ ->
println("Item")
}3.4 Lambda 与协程
kotlin
// suspend Lambda 作为参数
suspend fun fetchData(
url: String,
onSuccess: suspend (String) -> Unit,
onError: suspend (Throwable) -> Unit
) {
try {
val result = withContext(Dispatchers.IO) {
// 网络请求
"data"
}
onSuccess(result)
} catch (e: Exception) {
onError(e)
}
}
// 使用
lifecycleScope.launch {
fetchData(
url = "https://api.example.com/data",
onSuccess = { data ->
updateUI(data)
},
onError = { error ->
showError(error.message)
}
)
}
// 返回 suspend 函数
fun createDataLoader(): suspend (String) -> String {
return { url ->
withContext(Dispatchers.IO) {
// 加载数据
"data from $url"
}
}
}3.5 Lambda 捕获变量
kotlin
// Lambda 可以捕获外部变量
fun createCounter(): () -> Int {
var count = 0
return {
count++
count
}
}
// 使用
val counter = createCounter()
println(counter()) // 1
println(counter()) // 2
println(counter()) // 3
// 捕获 this
class MyClass {
private var value = 10
fun getPrinter(): () -> Unit {
return {
println(value) // 捕获外部类的 value
}
}
}
// 明确指定 this
class Outer {
val value = "Outer"
inner class Inner {
val value = "Inner"
fun print() {
val block: () -> Unit = {
println(value) // Inner.value
println(this@Inner.value) // Inner.value
println(this@Outer.value) // Outer.value
}
block()
}
}
}4. 返回函数
4.1 基础语法
kotlin
// 返回 Lambda
fun getAdder(x: Int): (Int) -> Int {
return { y -> x + y }
}
// 使用
val add5 = getAdder(5)
println(add5(3)) // 8
// 返回匿名函数
fun getMultiplier(factor: Int): (Int) -> Int {
return fun(x): Int {
return x * factor
}
}
// 简化写法
fun getMultiplier2(factor: Int) = { x: Int -> x * factor }4.2 返回带接收者的函数
kotlin
// 返回带接收者的函数
fun createBuilder(): StringBuilder.() -> Unit {
return {
append("Hello")
append(" ")
append("World")
}
}
// 使用
val sb = StringBuilder()
sb.createBuilder()()
println(sb.toString()) // "Hello World"
// 更实用的例子
fun <T> createFilter(predicate: (T) -> Boolean): (T) -> Boolean {
return predicate
}
// 使用
val isEven = createFilter { it % 2 == 0 }
println(listOf(1, 2, 3, 4).filter(isEven)) // [2, 4]4.3 工厂函数模式
kotlin
// 1. 策略工厂
interface SortStrategy {
fun <T : Comparable<T>> sort(list: List<T>): List<T>
}
class QuickSortStrategy : SortStrategy {
override fun <T : Comparable<T>> sort(list: List<T>): List<T> {
// 快速排序实现
return list.sorted()
}
}
class MergeSortStrategy : SortStrategy {
override fun <T : Comparable<T>> sort(list: List<T>): List<T> {
// 归并排序实现
return list.sorted()
}
}
fun getSortStrategy(algorithm: String): SortStrategy {
return when (algorithm) {
"quick" -> QuickSortStrategy()
"merge" -> MergeSortStrategy()
else -> QuickSortStrategy()
}
}
// 2. 验证器工厂
typealias Validator<T> = (T) -> Boolean
fun <T> createValidator(
vararg validations: Validator<T>
): Validator<T> {
return { value ->
validations.all { it(value) }
}
}
// 使用
val emailValidator: Validator<String> = { it.contains("@") }
val lengthValidator: Validator<String> = { it.length >= 5 }
val combinedValidator = createValidator(emailValidator, lengthValidator)
println(combinedValidator("test@example.com")) // true
println(combinedValidator("short")) // false
// 3. 转换器工厂
fun <T, R> createMapper(transform: (T) -> R): (List<T>) -> List<R> {
return { list -> list.map(transform) }
}
// 使用
val stringMapper = createMapper { it.toString() }
println(stringMapper(listOf(1, 2, 3))) // ["1", "2", "3"]4.4 柯里化(Currying)
kotlin
// 柯里化:将多参数函数转换为单参数函数链
fun add(a: Int): (Int) -> Int {
return { b -> a + b }
}
// 使用
val add5 = add(5)
println(add5(3)) // 8
// 直接调用
println(add(5)(3)) // 8
// 通用柯里化
fun <P1, P2, R> curry(f: (P1, P2) -> R): (P1) -> (P2) -> R {
return { p1 -> { p2 -> f(p1, p2) } }
}
// 使用
val sum = { a: Int, b: Int -> a + b }
val curriedSum = curry(sum)
println(curriedSum(5)(3)) // 8
// 三个参数的柯里化
fun <P1, P2, P3, R> curry(f: (P1, P2, P3) -> R): (P1) -> (P2) -> (P3) -> R {
return { p1 -> { p2 -> { p3 -> f(p1, p2, p3) } } }
}4.5 部分应用(Partial Application)
kotlin
// 部分应用:固定部分参数,返回新函数
fun multiply(a: Int, b: Int, c: Int): Int = a * b * c
// 固定第一个参数
fun multiplyBy2(b: Int, c: Int) = multiply(2, b, c)
// 使用 Lambda 实现部分应用
fun <P1, P2, P3, R> partial1(
f: (P1, P2, P3) -> R,
p1: P1
): (P2, P3) -> R {
return { p2, p3 -> f(p1, p2, p3) }
}
// 使用
val multiplyBy2Partial = partial1(::multiply, 2)
println(multiplyBy2Partial(3, 4)) // 245. 内联高阶函数
5.1 inline 关键字的作用
kotlin
// 普通高阶函数
fun <T> List<T>.forEach(action: (T) -> Unit) {
for (element in this) action(element)
}
// 编译后(伪代码)
// 1. 创建 Lambda 对象
// 2. 调用 forEach 方法
// 3. Lambda 对象在循环中被调用
// 内联高阶函数
inline fun <T> List<T>.forEach(action: (T) -> Unit) {
for (element in this) action(element)
}
// 编译后(伪代码)
// 直接展开 Lambda 内容
for (element in this) {
// Lambda 内容直接在这里
println(element)
}5.2 noinline 和 crossinline
kotlin
// noinline:禁止特定 Lambda 参数内联
inline fun test(
inlineParam: () -> Unit,
noinline noInlineParam: () -> Unit
) {
inlineParam() // 内联
noInlineParam() // 不内联,可以作为对象传递
// 可以将 noInlineParam 传递给其他函数
executeLater(noInlineParam)
}
fun executeLater(action: () -> Unit) {
// 延迟执行
action()
}
// crossinline:禁止非局部返回
inline fun test(crossinline block: () -> Unit) {
val runnable = Runnable {
block() // 不能在这里 return
}
Thread(runnable).start()
}
// ❌ 错误:crossinline 禁止非局部返回
// fun example() {
// test {
// return // ❌ 错误:不能从外部函数返回
// }
// }
// ✅ 正确:使用标签返回
fun example() {
test {
return@example // ✅ 从 example 返回
}
}5.3 内联函数的实际场景
kotlin
// 1. 资源管理(use)
inline fun <T : Closeable, R> T.use(block: (T) -> R): R {
var exception: Throwable? = null
try {
return block(this)
} catch (e: Throwable) {
exception = e
throw e
} finally {
try {
close()
} catch (e: Throwable) {
if (exception == null) throw e
exception.addSuppressed(e)
}
}
}
// 使用
FileInputStream("file.txt").use { fis ->
// 自动关闭,无需 finally
val content = fis.readBytes()
}
// 2. 同步锁
inline fun <T> Any.synchronized(block: () -> T): T {
return kotlin.synchronized(this, block)
}
// 使用
val lock = Any()
val result = lock.synchronized {
// 线程安全操作
sharedData
}
// 3. 运行作用域
inline fun <T, R> T.let(block: (T) -> R): R {
return block(this)
}
inline fun <T, R> T.run(block: T.() -> R): R {
return block()
}
inline fun <T> T.apply(block: T.() -> Unit): T {
block()
return this
}
inline fun <T> T.also(block: (T) -> Unit): T {
block(this)
return this
}5.4 reified 泛型
内联函数可以使用 reified 泛型,在运行时获取类型信息:
kotlin
// 普通泛型(类型擦除)
fun <T> isInstanceOf(obj: Any): Boolean {
// return obj is T // ❌ 错误:类型信息在运行时被擦除
return false
}
// reified 泛型
inline fun <reified T> isInstanceOf(obj: Any): Boolean {
return obj is T // ✅ 正确:内联后可以获取类型
}
// 使用
println(isInstanceOf<String>("Hello")) // true
println(isInstanceOf<Int>(42)) // true
println(isInstanceOf<String>(42)) // false
// 实际应用:过滤类型
inline fun <reified T> List<*>.filterIsInstance(): List<T> {
return this.filterIsInstance<T>()
}
// 使用
val list = listOf(1, "hello", 2, "world", 3)
val strings = list.filterIsInstance<String>() // ["hello", "world"]
val ints = list.filterIsInstance<Int>() // [1, 2, 3]
// 实际应用:启动 Activity
inline fun <reified T : Activity> Context.startActivity() {
val intent = Intent(this, T::class.java)
startActivity(intent)
}
// 使用
context.startActivity<DetailActivity>()5.5 内联类的性能优化
kotlin
// 内联类(值类)- Kotlin 1.5+
@JvmInline
value class UserId(val value: String)
@JvmInline
value class Email(val value: String)
// 编译后直接是 String,没有对象开销
fun sendEmail(userId: UserId, email: Email) {
// userId 和 email 在运行时就是 String
}
// 内联类可以有方法
@JvmInline
value class Percent(val value: Int) {
fun toDouble(): Double = value / 100.0
operator fun plus(other: Percent): Percent {
return Percent(this.value + other.value)
}
}
// 使用
val p1 = Percent(50)
val p2 = Percent(30)
val p3 = p1 + p2 // Percent(80)
println(p3.toDouble()) // 0.86. 标准库高阶函数
6.1 集合操作函数
kotlin
val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
// 转换操作符
numbers.map { it * 2 } // [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
numbers.mapIndexed { i, v -> i * v } // [0, 2, 6, 12, 20, ...]
numbers.flatMap { listOf(it, it * 2) } // [1, 2, 2, 4, 3, 6, ...]
// 过滤操作符
numbers.filter { it % 2 == 0 } // [2, 4, 6, 8, 10]
numbers.filterNot { it % 2 == 0 } // [1, 3, 5, 7, 9]
numbers.filterIndexed { i, v -> i % 2 == 0 } // [1, 3, 5, 7, 9]
// 取/舍操作符
numbers.take(3) // [1, 2, 3]
numbers.takeLast(3) // [8, 9, 10]
numbers.takeWhile { it < 5 } // [1, 2, 3, 4]
numbers.drop(3) // [4, 5, 6, 7, 8, 9, 10]
numbers.dropWhile { it < 5 } // [5, 6, 7, 8, 9, 10]
// 查找操作符
numbers.find { it > 5 } // 6
numbers.findLast { it > 5 } // 10
numbers.indexOfFirst { it > 5 } // 5
numbers.indexOfLast { it > 5 } // 9
// 判断操作符
numbers.any { it > 5 } // true
numbers.all { it > 0 } // true
numbers.none { it < 0 } // true
numbers.contains(5) // true6.2 分组和分区
kotlin
val numbers = listOf(1, 2, 3, 4, 5, 6)
// 分组
numbers.groupBy { it % 2 }
// {1=[1, 3, 5], 0=[2, 4, 6]}
numbers.groupBy({ it % 2 }, { it * 2 })
// {1=[2, 6, 10], 0=[4, 8, 12]}
// 分区
numbers.partition { it % 2 == 0 }
// ([2, 4, 6], [1, 3, 5])
// 切片
numbers.chunked(2)
// [[1, 2], [3, 4], [5, 6]]
numbers.chunked(3)
// [[1, 2, 3], [4, 5, 6]]
// 窗口
numbers.windowed(3)
// [[1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6], [5, 6]]
numbers.windowed(3, step = 2)
// [[1, 2, 3], [3, 4, 5], [5, 6]]6.3 折叠和归约
kotlin
val numbers = listOf(1, 2, 3, 4, 5)
// fold(带初始值)
val sum = numbers.fold(0) { acc, num -> acc + num } // 15
val product = numbers.fold(1) { acc, num -> acc * num } // 120
// foldRight(从右到左)
val result = numbers.foldRight("") { num, acc -> "$acc$num" } // "54321"
// reduce(无初始值,至少一个元素)
val sum2 = numbers.reduce { acc, num -> acc + num } // 15
// reduceRight
val result2 = numbers.reduceRight { num, acc -> "$acc$num" } // "54321"
// runningFold(累积过程)
val runningSum = numbers.runningFold(0) { acc, num -> acc + num }
// [0, 1, 3, 6, 10, 15]
// runningReduce
val runningProduct = numbers.runningReduce { acc, num -> acc * num }
// [1, 2, 6, 24, 120]6.4 组合操作符
kotlin
val list1 = listOf(1, 2, 3)
val list2 = listOf("a", "b", "c")
// zip(组合两个集合)
list1.zip(list2)
// [(1, "a"), (2, "b"), (3, "c")]
list1.zip(list2) { num, str -> "$num$str" }
// ["1a", "2b", "3c"]
// unzip(解压缩)
val pairs = listOf(1 to "a", 2 to "b", 3 to "c")
val (numbers, letters) = pairs.unzip()
// numbers = [1, 2, 3], letters = ["a", "b", "c"]
// 多个集合的 zip
list1.zip(list2).zip(listOf(true, false, true))
// [((1, "a"), true), ((2, "b"), false), ((3, "c"), true)]6.5 关联操作符
kotlin
val list = listOf("a", "b", "c")
// associate(创建 Map)
list.associate { it to it.uppercase() }
// {"a"="A", "b"="B", "c"="C"}
list.associateWith { it.length }
// {"a"=1, "b"=1, "c"=1}
list.associateBy { it.uppercase() }
// {"A"="a", "B"="b", "C"="c"}
// toMap
list.map { it to it.length }.toMap()
// {"a"=1, "b"=1, "c"=1}6.6 序列(Sequence)操作
kotlin
// 序列:惰性求值,适合大数据集
val sequence = sequenceOf(1, 2, 3, 4, 5)
.filter {
println("Filter: $it")
it % 2 == 0
}
.map {
println("Map: $it")
it * 2
}
// 不会执行任何操作(惰性)
// 终端操作触发计算
val result = sequence.take(2).toList()
// 输出:
// Filter: 1
// Filter: 2
// Map: 2
// Filter: 3
// Filter: 4
// Map: 4
// 与 List 对比
val listResult = listOf(1, 2, 3, 4, 5)
.filter {
println("Filter: $it")
it % 2 == 0
}
.map {
println("Map: $it")
it * 2
}
.take(2)
// 输出:
// Filter: 1
// Filter: 2
// Filter: 3
// Filter: 4
// Filter: 5
// Map: 2
// Map: 4
// (所有元素都处理了,即使只取 2 个)6.7 Android 常用高阶函数
kotlin
// 1. LiveData/Flow 操作
fun <T> LiveData<T>.observeOnce(owner: LifecycleOwner, observer: Observer<T>) {
observe(owner, object : Observer<T> {
override fun onChanged(value: T) {
observer.onChanged(value)
removeObserver(this)
}
})
}
// 2. View 操作
fun View.doOnLayout(action: (View) -> Unit) {
if (isLaidOut) {
action(this)
} else {
addOnLayoutChangeListener { view, _, _, _, _, _, _, _, _ ->
view.removeOnLayoutChangeListener(this)
action(view)
}
}
}
fun View.doOnPreDraw(action: (View) -> Unit) {
viewTreeObserver.addOnPreDrawListener(object : ViewTreeObserver.OnPreDrawListener {
override fun onPreDraw(): Boolean {
viewTreeObserver.removeOnPreDrawListener(this)
action(this@doOnPreDraw)
return true
}
})
}
// 3. 协程作用域
fun CoroutineScope.launchWhenStarted(block: suspend CoroutineScope.() -> Unit): Job {
return launch {
lifecycleFlow.filter { it >= Lifecycle.State.STARTED }.collect {
block()
}
}
}
// 4. 结果处理
sealed class Result<out T> {
data class Success<T>(val data: T) : Result<T>()
data class Error(val exception: Throwable) : Result<Nothing>()
}
fun <T, R> Result<T>.map(transform: (T) -> R): Result<R> {
return when (this) {
is Result.Success -> Result.Success(transform(data))
is Result.Error -> this
}
}
fun <T> Result<T>.onSuccess(action: (T) -> Unit): Result<T> {
return when (this) {
is Result.Success -> {
action(data)
this
}
is Result.Error -> this
}
}
fun <T> Result<T>.onError(action: (Throwable) -> Unit): Result<T> {
return when (this) {
is Result.Success -> this
is Result.Error -> {
action(exception)
this
}
}
}7. 面试考点汇总
7.1 基础问题
Q1: 什么是高阶函数?举例说明。
kotlin
// 答案要点:
// 1. 接受函数作为参数的函数
// 2. 或返回函数的函数
// 3. 标准库中的 map、filter、forEach 都是高阶函数
// 接受函数参数
fun operate(a: Int, b: Int, operation: (Int, Int) -> Int): Int {
return operation(a, b)
}
// 返回函数
fun getMultiplier(factor: Int): (Int) -> Int {
return { x -> x * factor }
}Q2: Lambda 表达式的语法是什么?
kotlin
// 答案要点:
// 1. { 参数 -> 函数体 }
// 2. 单个参数可以用 it
// 3. 可以放在括号外(尾随 Lambda)
// 4. 类型可以推断
// 完整语法
val sum = { a: Int, b: Int -> a + b }
// 类型推断
val sum: (Int, Int) -> Int = { a, b -> a + b }
// 单个参数
val double: (Int) -> Int = { it * 2 }
// 尾随 Lambda
list.map { it * 2 }Q3: 函数类型如何声明?
kotlin
// 答案要点:
// 1. (参数类型,...) -> 返回类型
// 2. 可以存储为变量
// 3. 可以作为参数和返回值
val func: (Int, Int) -> Int = { a, b -> a + b }
// 无参数
val greet: () -> String = { "Hello" }
// 无返回值
val print: () -> Unit = { println("Hello") }
// 带接收者
val block: StringBuilder.() -> Unit = { append("Hello") }7.2 进阶问题
Q4: inline 关键字的作用是什么?
kotlin
// 答案要点:
// 1. 将 Lambda 代码内联到调用处
// 2. 避免 Lambda 对象创建开销
// 3. 支持非局部返回
// 4. 需要 reified 时使用
inline fun <T> List<T>.forEach(action: (T) -> Unit) {
for (element in this) action(element)
}
// 内联后直接展开
for (element in this) {
println(element) // Lambda 内容直接在这里
}Q5: noinline 和 crossinline 的区别?
kotlin
// 答案要点:
// 1. noinline 禁止特定 Lambda 内联
// 2. crossinline 禁止非局部返回
// 3. noinline 用于将 Lambda 传递给其他函数
// 4. crossinline 用于在另一个 Lambda 中调用
inline fun test(
inlineParam: () -> Unit,
noinline noInlineParam: () -> Unit
) {
inlineParam() // 内联
executeLater(noInlineParam) // 可以作为对象传递
}
inline fun test2(crossinline block: () -> Unit) {
val runnable = Runnable {
block() // 不能 return
}
}Q6: reified 泛型是什么?如何使用?
kotlin
// 答案要点:
// 1. 只能在 inline 函数中使用
// 2. 在运行时保留类型信息
// 3. 可以用于 is/as 检查
// 4. 常用于过滤、启动 Activity 等
inline fun <reified T> isInstanceOf(obj: Any): Boolean {
return obj is T
}
inline fun <reified T> List<*>.filterIsInstance(): List<T> {
return this.filterIsInstance<T>()
}
inline fun <reified T : Activity> Context.startActivity() {
val intent = Intent(this, T::class.java)
startActivity(intent)
}7.3 原理问题
Q7: 高阶函数的性能开销?
kotlin
// 答案要点:
// 1. Lambda 会创建对象(函数对象)
// 2. 有分配和 GC 开销
// 3. 使用 inline 可以消除开销
// 4. 基本类型参数注意装箱
// 普通高阶函数
list.forEach { println(it) }
// 1. 创建 Lambda 对象
// 2. 调用 forEach 方法
// 3. 在循环中调用 Lambda
// 内联高阶函数
inline fun <T> List<T>.forEach(action: (T) -> Unit)
// 直接展开 Lambda 内容,无对象创建Q8: 尾随 Lambda 的规则?
kotlin
// 答案要点:
// 1. 最后一个参数是函数时可以放在括号外
// 2. 如果只有 Lambda 参数,括号可以省略
// 3. 提高代码可读性
// 尾随 Lambda
list.map { it * 2 }
// 只有 Lambda 参数
run {
println("Hello")
}
// 多个参数时
list.fold(0) { acc, num ->
acc + num
}7.4 实战问题
Q9: 如何实现一个重试机制的高阶函数?
kotlin
// 答案要点:
// 1. 接受 suspend Lambda 作为参数
// 2. 循环执行直到成功或达到最大次数
// 3. 使用 delay 实现退避
// 4. 抛出最后的异常
suspend fun <T> retry(
times: Int = 3,
delayMs: Long = 1000,
operation: suspend () -> T
): T {
var lastException: Exception? = null
repeat(times) { attempt ->
try {
return operation()
} catch (e: Exception) {
lastException = e
if (attempt < times - 1) {
delay(delayMs)
}
}
}
throw lastException ?: Exception("Unknown error")
}
// 使用
val result = retry(times = 3, delayMs = 2000) {
api.loadData()
}Q10: 如何使用高阶函数实现 DSL?
kotlin
// 答案要点:
// 1. 使用带接收者的 Lambda
// 2. 使用 apply/scope 函数
// 3. 提供清晰的配置 API
// 4. 返回构建的对象
class Dialog {
var title: String = ""
var message: String = ""
var positiveButton: String = "OK"
fun show() {
println("Dialog: $title - $message")
}
}
fun dialog(configure: Dialog.() -> Unit): Dialog {
return Dialog().apply(configure)
}
// 使用
dialog {
title = "提示"
message = "确定要删除吗?"
positiveButton = "删除"
}.show()Q11: 标准库中有哪些常用的高阶函数?
kotlin
// 答案要点:
// 1. 转换:map、flatMap、mapIndexed
// 2. 过滤:filter、filterNot、filterIndexed
// 3. 取/舍:take、takeWhile、drop、dropWhile
// 4. 查找:find、findLast、indexOfFirst
// 5. 判断:any、all、none、contains
// 6. 折叠:fold、reduce、foldRight
// 7. 分组:groupBy、partition、chunked
// 8. 组合:zip、unzip
val numbers = listOf(1, 2, 3, 4, 5)
numbers.map { it * 2 } // 转换
numbers.filter { it % 2 == 0 } // 过滤
numbers.take(3) // 取
numbers.find { it > 3 } // 查找
numbers.any { it > 3 } // 判断
numbers.fold(0) { a, b -> a + b } // 折叠
numbers.groupBy { it % 2 } // 分组最佳实践总结
✅ 推荐做法
kotlin
// 1. 使用标准库高阶函数
list.map { it * 2 }
list.filter { it > 0 }
// 2. 使用尾随 Lambda
list.fold(0) { acc, num ->
acc + num
}
// 3. 内联高阶函数
inline fun <T> List<T>.forEach(action: (T) -> Unit)
// 4. 使用 reified 泛型
inline fun <reified T> List<*>.filterIsInstance(): List<T>
// 5. 清晰的 Lambda 参数命名
list.map { number -> number * 2 }❌ 避免做法
kotlin
// 1. 避免过长的 Lambda
list.map {
// 几十行代码
}
// 2. 避免嵌套过深
list.map { x ->
list2.map { y ->
list3.map { z ->
// ...
}
}
}
// 3. 避免不必要的内联
// 不是所有高阶函数都需要 inline
// 4. 避免忽略 Lambda 参数
list.forEach {
// 不使用 it
}参考资料
最后更新:2026-04-14