3-1-1 高阶函数-Lambda表达式深入

19 阅读4分钟

Kotlin Lambda表达式深入应用

Lambda表达式是Kotlin函数式编程的核心特性之一,它让代码更简洁、更具表达力。下面我将从基础到高级,深入探讨Lambda的应用。

1. Lambda基础语法

基本Lambda表达式

// 传统方式
val sum = { x: Int, y: Int -> x + y }

// 类型推断
val sum: (Int, Int) -> Int = { x, y -> x + y }

// 调用
println(sum(3, 5)) // 输出: 8

Lambda作为参数

fun processNumbers(numbers: List<Int>, processor: (Int) -> Int): List<Int> {
    return numbers.map(processor)
}

val result = processNumbers(listOf(1, 2, 3)) { it * 2 }
// 结果: [2, 4, 6]

2. 高级Lambda特性

带接收者的Lambda (DSL构建)

// 定义HTML构建器
class Html {
    private val children = mutableListOf<String>()
    
    fun body(init: Html.() -> Unit) {
        val bodyContent = Html().apply(init)
        children.add("<body>${bodyContent.children.joinToString("")}</body>")
    }
    
    fun div(init: Html.() -> Unit) {
        val divContent = Html().apply(init)
        children.add("<div>${divContent.children.joinToString("")}</div>")
    }
    
    fun text(content: String) {
        children.add(content)
    }
    
    override fun toString(): String = children.joinToString("")
}

// 使用
val html = Html().apply {
    body {
        div {
            text("Hello, Kotlin!")
        }
    }
}

Lambda与集合操作

data class Person(val name: String, val age: Int, val city: String)

val people = listOf(
    Person("Alice", 29, "New York"),
    Person("Bob", 31, "San Francisco"),
    Person("Charlie", 25, "New York"),
    Person("Diana", 35, "Chicago")
)

// 链式操作
val result = people
    .filter { it.city == "New York" }
    .sortedByDescending { it.age }
    .groupBy { it.age > 30 }
    .mapValues { (key, value) -> value.map { it.name } }

// 自定义集合操作
fun <T> List<T>.filterIndexed(predicate: (Int, T) -> Boolean): List<T> {
    val result = mutableListOf<T>()
    forEachIndexed { index, value ->
        if (predicate(index, value)) result.add(value)
    }
    return result
}

val filtered = listOf(1, 2, 3, 4, 5).filterIndexed { index, value -> 
    index % 2 == 0 && value > 2
}

3. Lambda性能优化

内联函数

// 内联函数避免Lambda开销
inline fun <T> measureTime(block: () -> T): Pair<T, Long> {
    val start = System.nanoTime()
    val result = block()
    val end = System.nanoTime()
    return result to (end - start)
}

// 使用
val (result, time) = measureTime {
    // 耗时操作
    Thread.sleep(1000)
    "Done"
}

非内联的crossinline和noinline

// crossinline - 禁止非局部返回
inline fun runAsync(crossinline block: () -> Unit) {
    Thread {
        block() // 这里不能使用return
    }.start()
}

// noinline - 指定不内联某个Lambda
inline fun process(
    onSuccess: () -> Unit,
    noinline onError: (Exception) -> Unit
) {
    try {
        // 操作
        onSuccess()
    } catch (e: Exception) {
        // onError不会被内联
        onError(e)
    }
}

4. Lambda的实用模式

缓存/记忆化模式

fun <T, R> memoize(fn: (T) -> R): (T) -> R {
    val cache = mutableMapOf<T, R>()
    return { key ->
        cache.getOrPut(key) { fn(key) }
    }
}

// 使用
val expensiveCalculation = { n: Int ->
    Thread.sleep(1000)
    n * n
}

val memoizedCalculation = memoize(expensiveCalculation)
println(memoizedCalculation(5)) // 计算并缓存
println(memoizedCalculation(5)) // 从缓存获取

函数柯里化

fun <A, B, C> curry(f: (A, B) -> C): (A) -> (B) -> C = 
    { a -> { b -> f(a, b) } }

fun <A, B, C, D> curry(f: (A, B, C) -> D): (A) -> (B) -> (C) -> D = 
    { a -> { b -> { c -> f(a, b, c) } } }

// 使用
val add = { a: Int, b: Int -> a + b }
val curriedAdd = curry(add)
val add5 = curriedAdd(5)
println(add5(3)) // 8

5. Lambda与协程结合

import kotlinx.coroutines.*

// Lambda作为协程构建器参数
fun launchMultipleTasks() = runBlocking {
    val jobs = List(10) { index ->
        launch {
            delay((1000L..2000L).random())
            println("Task $index completed on ${Thread.currentThread().name}")
        }
    }
    jobs.forEach { it.join() }
}

// 高阶函数与协程
suspend fun <T, R> withTimeoutOrNull(
    timeout: Long,
    block: suspend () -> T,
    onTimeout: suspend () -> R
): Any? = coroutineScope {
    try {
        withTimeout(timeout) { block() }
    } catch (e: TimeoutCancellationException) {
        onTimeout()
    }
}

6. DSL设计模式

// SQL查询DSL
class QueryBuilder {
    private var selectColumns = mutableListOf<String>()
    private var fromTable: String? = null
    private var whereClause: String? = null
    
    fun select(vararg columns: String) {
        selectColumns.addAll(columns)
    }
    
    fun from(table: String) {
        fromTable = table
    }
    
    fun where(condition: String) {
        whereClause = condition
    }
    
    fun build(): String {
        val columns = if (selectColumns.isEmpty()) "*" else selectColumns.joinToString(", ")
        val where = whereClause?.let { " WHERE $it" } ?: ""
        return "SELECT $columns FROM ${fromTable ?: "unknown"}$where"
    }
}

// 使用DSL
fun query(init: QueryBuilder.() -> Unit): QueryBuilder {
    return QueryBuilder().apply(init)
}

val sql = query {
    select("id", "name", "email")
    from("users")
    where("age > 18")
}.build()

7. Lambda与类型安全构建器

// 类型安全的HTML构建器
open class Tag(val name: String) {
    private val children = mutableListOf<Tag>()
    protected val attributes = mutableMapOf<String, String>()
    
    operator fun String.unaryPlus() {
        children.add(TextTag(this))
    }
    
    fun <T : Tag> initTag(tag: T, init: T.() -> Unit): T {
        tag.init()
        children.add(tag)
        return tag
    }
    
    override fun toString(): String {
        return "<$name${attributes.entries.joinToString("") { " ${it.key}=\"${it.value}\"" }}" +
               if (children.isEmpty()) "/>" 
               else ">${children.joinToString("")}</$name>"
    }
}

class TextTag(val text: String) : Tag("") {
    override fun toString(): String = text
}

fun html(init: HTML.() -> Unit): HTML {
    return HTML().apply(init)
}

class HTML : Tag("html") {
    fun head(init: Head.() -> Unit) = initTag(Head(), init)
    fun body(init: Body.() -> Unit) = initTag(Body(), init)
}

class Head : Tag("head") {
    fun title(init: Title.() -> Unit) = initTag(Title(), init)
}

class Title : Tag("title")
class Body : Tag("body") {
    fun h1(init: H1.() -> Unit) = initTag(H1(), init)
    fun p(init: P.() -> Unit) = initTag(P(), init)
}

class H1 : Tag("h1")
class P : Tag("p")

// 使用
val document = html {
    head {
        title { +"Kotlin DSL" }
    }
    body {
        h1 { +"Hello Kotlin DSL" }
        p { 
            +"This is a paragraph" 
        }
    }
}

8. 性能考虑和最佳实践

避免不必要的Lambda创建

// 不好: 在循环中重复创建Lambda
fun processList(items: List<String>) {
    items.forEach { item ->
        // 每次循环都创建新的Lambda
        processItem { println(item) }
    }
}

// 好: 复用Lambda
fun processListOptimized(items: List<String>) {
    val processor: (String) -> Unit = { item ->
        processItem { println(item) }
    }
    items.forEach(processor)
}

使用序列进行惰性求值

val largeList = (1..1_000_000).toList()

// 急切求值 - 创建中间集合
val result1 = largeList
    .filter { it % 2 == 0 }  // 创建500k元素的列表
    .map { it * 2 }          // 再次创建500k元素的列表
    .take(10)                // 只取前10个

// 惰性求值 - 无中间集合
val result2 = largeList.asSequence()
    .filter { it % 2 == 0 }  // 惰性过滤
    .map { it * 2 }          // 惰性映射
    .take(10)                // 只处理前10个元素
    .toList()

总结

Kotlin的Lambda表达式提供了强大的函数式编程能力:

  1. 简洁性:减少样板代码,提高可读性
  2. 表达力:支持DSL设计,创建领域特定语言
  3. 函数组合:支持高阶函数和函数组合
  4. 性能优化:通过内联函数减少运行时开销
  5. 类型安全:编译时类型检查保证安全性

掌握Lambda的高级用法可以让你编写出更优雅、更高效的Kotlin代码。实际应用中,建议根据具体场景选择合适的技术,避免过度设计。