2-2-25 快速掌握Kotlin-函数式编程

35 阅读3分钟

Kotlin 函数式编程全面指南

Kotlin 完美融合了面向对象和函数式编程范式,提供了强大且简洁的函数式编程能力。

1. 核心概念

1.1 函数作为一等公民

// 函数可以作为变量
val add: (Int, Int) -> Int = { a, b -> a + b }

// 函数可以作为参数
fun calculate(x: Int, y: Int, operation: (Int, Int) -> Int): Int {
    return operation(x, y)
}

// 函数可以作为返回值
fun getMultiplier(factor: Int): (Int) -> Int {
    return { value -> value * factor }
}

fun main() {
    println(calculate(5, 3, add))  // 8
    
    val triple = getMultiplier(3)
    println(triple(5))  // 15
}

1.2 不可变性

// 不可变集合
val immutableList = listOf(1, 2, 3)
val immutableMap = mapOf("a" to 1, "b" to 2)

// 可变集合(需要时使用)
val mutableList = mutableListOf(1, 2, 3)

// 数据类默认是不可变的
data class User(val name: String, val age: Int)

fun main() {
    val user = User("Alice", 30)
    // user.age = 31  // 编译错误
    val updatedUser = user.copy(age = 31)  // 创建新实例
}

2. Lambda 表达式与高阶函数

2.1 Lambda 语法

// 完整语法
val sum: (Int, Int) -> Int = { x: Int, y: Int -> x + y }

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

// 单参数时可用 it
val square: (Int) -> Int = { it * it }

// 多行 Lambda
val processString = { str: String ->
    val trimmed = str.trim()
    trimmed.uppercase()
}

fun main() {
    println(sum(3, 4))  // 7
    println(square(5))   // 25
    println(processString(" hello "))  // HELLO
}

2.2 高阶函数实践

// 接受函数作为参数
fun List<Int>.customFilter(predicate: (Int) -> Boolean): List<Int> {
    val result = mutableListOf<Int>()
    for (item in this) {
        if (predicate(item)) {
            result.add(item)
        }
    }
    return result
}

// 返回函数
fun createLogger(prefix: String): (String) -> Unit {
    return { message -> println("[$prefix] $message") }
}

// 内联函数优化
inline fun measureTime(block: () -> Unit): Long {
    val start = System.nanoTime()
    block()
    return System.nanoTime() - start
}

fun main() {
    val numbers = listOf(1, 2, 3, 4, 5)
    val evenNumbers = numbers.customFilter { it % 2 == 0 }
    println(evenNumbers)  // [2, 4]
    
    val debugLogger = createLogger("DEBUG")
    debugLogger("Application started")
    
    val duration = measureTime {
        Thread.sleep(100)
    }
    println("Time taken: ${duration / 1_000_000}ms")
}

3. 集合函数式操作

3.1 转换操作

fun main() {
    val numbers = listOf(1, 2, 3, 4, 5)
    
    // map - 转换每个元素
    val squared = numbers.map { it * it }
    println(squared)  // [1, 4, 9, 16, 25]
    
    // flatMap - 展平嵌套集合
    val nested = listOf(listOf(1, 2), listOf(3, 4))
    val flattened = nested.flatMap { it }
    println(flattened)  // [1, 2, 3, 4]
    
    // mapIndexed - 使用索引
    val withIndex = numbers.mapIndexed { index, value -> 
        "Item $index: $value" 
    }
    println(withIndex)  // [Item 0: 1, Item 1: 2, ...]
    
    // associate - 创建映射
    val squaresMap = numbers.associate { it to it * it }
    println(squaresMap)  // {1=1, 2=4, 3=9, 4=16, 5=25}
}

3.2 过滤操作

fun main() {
    val numbers = (1..10).toList()
    
    // filter - 基本过滤
    val evens = numbers.filter { it % 2 == 0 }
    
    // filterNot - 反向过滤
    val odds = numbers.filterNot { it % 2 == 0 }
    
    // filterIndexed - 基于索引过滤
    val firstHalf = numbers.filterIndexed { index, _ -> index < 5 }
    
    // filterIsInstance - 类型过滤
    val mixedList = listOf(1, "two", 3, "four", 5)
    val integers = mixedList.filterIsInstance<Int>()
    
    // takeWhile / dropWhile
    val takeWhile = numbers.takeWhile { it < 5 }  // [1, 2, 3, 4]
    val dropWhile = numbers.dropWhile { it < 5 }  // [5, 6, 7, 8, 9, 10]
}

3.3 聚合操作

fun main() {
    val numbers = listOf(1, 2, 3, 4, 5)
    
    // reduce - 累积操作
    val sum = numbers.reduce { acc, value -> acc + value }
    println(sum)  // 15
    
    // fold - 带初始值的累积
    val product = numbers.fold(1) { acc, value -> acc * value }
    println(product)  // 120
    
    // foldRight - 从右到左
    val concatenated = numbers.foldRight("") { value, acc -> "$value$acc" }
    println(concatenated)  // "54321"
    
    // max/min
    val max = numbers.maxOrNull()
    val min = numbers.minOrNull()
    
    // sum/sumOf
    val total = numbers.sum()
    val sumOfSquares = numbers.sumOf { it * it }
    
    // groupBy - 分组
    val words = listOf("apple", "banana", "cherry", "date")
    val byLength = words.groupBy { it.length }
    println(byLength)  // {5=[apple], 6=[banana, cherry], 4=[date]}
    
    // partition - 分割
    val (evens, odds) = numbers.partition { it % 2 == 0 }
    println("Evens: $evens, Odds: $odds")
}

3.4 查找操作

fun main() {
    val numbers = listOf(1, 2, 3, 4, 5)
    
    // find - 查找第一个匹配元素
    val firstEven = numbers.find { it % 2 == 0 }  // 2
    
    // first/last - 带条件
    val lastOdd = numbers.last { it % 2 == 1 }  // 5
    
    // single - 期望只有一个匹配元素
    val single = listOf(5).single { it > 3 }  // 5
    
    // any/all/none
    val hasEven = numbers.any { it % 2 == 0 }  // true
    val allPositive = numbers.all { it > 0 }   // true
    val noNegatives = numbers.none { it < 0 }  // true
    
    // count
    val evenCount = numbers.count { it % 2 == 0 }  // 2
}

4. 序列(Sequences)

序列是惰性求值的集合,适合处理大数据集。

fun main() {
    // 创建序列
    val sequence1 = sequenceOf(1, 2, 3, 4, 5)
    val sequence2 = (1..5).asSequence()
    val sequence3 = generateSequence(1) { it + 1 }.take(5)
    
    // 惰性求值示例
    val result = (1..1_000_000)
        .asSequence()
        .filter { 
            println("Filtering $it")
            it % 2 == 0 
        }
        .map { 
            println("Mapping $it")
            it * 2 
        }
        .take(3)  // 只处理前3个元素
        .toList()
    
    println(result)  // [4, 8, 12]
    
    // 无限序列
    val fibonacci = sequence {
        var a = 0
        var b = 1
        yield(a)
        yield(b)
        
        while (true) {
            val next = a + b
            yield(next)
            a = b
            b = next
        }
    }
    
    val first10Fibonacci = fibonacci.take(10).toList()
    println(first10Fibonacci)  // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
}

5. 函数组合与柯里化

5.1 函数组合

// 组合函数:f(g(x))
infix fun <A, B, C> ((B) -> C).compose(g: (A) -> B): (A) -> C {
    return { x -> this(g(x)) }
}

// 管道操作:g(f(x))
infix fun <A, B, C> ((A) -> B).andThen(f: (B) -> C): (A) -> C {
    return { x -> f(this(x)) }
}

fun main() {
    val add2 = { x: Int -> x + 2 }
    val multiplyBy3 = { x: Int -> x * 3 }
    val square = { x: Int -> x * x }
    
    // 组合:square(add2(x))
    val addThenSquare = square compose add2
    println(addThenSquare(3))  // (3+2)^2 = 25
    
    // 管道:multiplyBy3(square(x))
    val squareThenMultiply = square andThen multiplyBy3
    println(squareThenMultiply(4))  // (4^2)*3 = 48
    
    // 多函数组合
    val pipeline = add2 andThen multiplyBy3 andThen square
    println(pipeline(5))  // ((5+2)*3)^2 = 441
}

5.2 柯里化(Currying)

// 柯里化:将多参数函数转换为一系列单参数函数
fun <A, B, C> curry(f: (A, B) -> C): (A) -> (B) -> C {
    return { a -> { b -> f(a, b) } }
}

// 反柯里化
fun <A, B, C> uncurry(f: (A) -> (B) -> C): (A, B) -> C {
    return { a, b -> f(a)(b) }
}

// 部分应用
fun <A, B, C> partial(f: (A, B) -> C, a: A): (B) -> C {
    return { b -> f(a, b) }
}

fun main() {
    // 普通多参数函数
    val add: (Int, Int) -> Int = { a, b -> a + b }
    
    // 柯里化版本
    val curriedAdd = curry(add)
    val add5 = curriedAdd(5)
    println(add5(3))  // 8
    
    // 部分应用
    val multiplyBy10 = partial({ a: Int, b: Int -> a * b }, 10)
    println(multiplyBy10(7))  // 70
    
    // 实际应用:配置函数
    val createGreeting = { greeting: String, name: String -> "$greeting, $name!" }
    val sayHello = partial(createGreeting, "Hello")
    val sayHi = partial(createGreeting, "Hi")
    
    println(sayHello("Alice"))  // Hello, Alice!
    println(sayHi("Bob"))       // Hi, Bob!
}

6. 递归与尾递归优化

// 普通递归
fun factorial(n: Int): Int {
    return if (n <= 1) 1 else n * factorial(n - 1)
}

// 尾递归优化
tailrec fun factorialTailRec(n: Int, accumulator: Int = 1): Int {
    return if (n <= 1) accumulator 
           else factorialTailRec(n - 1, n * accumulator)
}

// 尾递归遍历树结构
sealed class Tree<T> {
    data class Node<T>(val value: T, val left: Tree<T>, val right: Tree<T>) : Tree<T>()
    object Empty : Tree<Nothing>()
}

tailrec fun <T> searchTree(tree: Tree<T>, target: T): Boolean = when (tree) {
    is Tree.Empty -> false
    is Tree.Node -> {
        if (tree.value == target) true
        else searchTree(tree.left, target) || searchTree(tree.right, target)
    }
}

fun main() {
    println(factorial(5))           // 120
    println(factorialTailRec(5))    // 120
    
    val tree = Tree.Node(1,
        Tree.Node(2, Tree.Empty, Tree.Empty),
        Tree.Node(3, Tree.Empty, Tree.Empty)
    )
    println(searchTree(tree, 2))  // true
    println(searchTree(tree, 4))  // false
}

7. 函数式错误处理

7.1 Either 模式

sealed class Either<out L, out R> {
    data class Left<out L>(val value: L) : Either<L, Nothing>()
    data class Right<out R>(val value: R) : Either<Nothing, R>()
    
    fun <T> fold(leftOp: (L) -> T, rightOp: (R) -> T): T = when (this) {
        is Left -> leftOp(value)
        is Right -> rightOp(value)
    }
    
    fun isLeft(): Boolean = this is Left
    fun isRight(): Boolean = this is Right
}

// Either 扩展函数
fun <L, R, T> Either<L, R>.map(f: (R) -> T): Either<L, T> = when (this) {
    is Either.Left -> Either.Left(value)
    is Either.Right -> Either.Right(f(value))
}

fun <L, R, T> Either<L, R>.flatMap(f: (R) -> Either<L, T>): Either<L, T> = when (this) {
    is Either.Left -> Either.Left(value)
    is Either.Right -> f(value)
}

// 使用示例
fun parseNumber(str: String): Either<String, Int> {
    return try {
        Either.Right(str.toInt())
    } catch (e: NumberFormatException) {
        Either.Left("Failed to parse: $str")
    }
}

fun divide(a: Int, b: Int): Either<String, Int> {
    return if (b == 0) {
        Either.Left("Division by zero")
    } else {
        Either.Right(a / b)
    }
}

fun main() {
    val result = parseNumber("10")
        .flatMap { a -> parseNumber("2").flatMap { b -> divide(a, b) } }
    
    result.fold(
        leftOp = { error -> println("Error: $error") },
        rightOp = { value -> println("Result: $value") }
    )  // Result: 5
}

7.2 Result 类型

typealias Result<T> = Either<String, T>

fun <T, R> Result<T>.mapResult(transform: (T) -> R): Result<R> {
    return when (this) {
        is Either.Left -> Either.Left(value)
        is Either.Right -> Either.Right(transform(value))
    }
}

fun <T, R> Result<T>.flatMapResult(transform: (T) -> Result<R>): Result<R> {
    return when (this) {
        is Either.Left -> Either.Left(value)
        is Either.Right -> transform(value)
    }
}

// 管道操作
infix fun <T, R> Result<T>.`then`(transform: (T) -> Result<R>): Result<R> {
    return flatMapResult(transform)
}

// 使用示例
fun processUserInput(input: String): Result<Int> {
    return parseNumber(input)
        .then { validatePositive(it) }
        .then { processValue(it) }
}

fun validatePositive(n: Int): Result<Int> {
    return if (n > 0) Either.Right(n)
    else Either.Left("Number must be positive")
}

fun processValue(n: Int): Result<Int> {
    return Either.Right(n * 2)
}

fun main() {
    val results = listOf("10", "-5", "abc")
    
    results.forEach { input ->
        val result = processUserInput(input)
        result.fold(
            leftOp = { println("Input '$input' failed: $it") },
            rightOp = { println("Input '$input' result: $it") }
        )
    }
}

8. 函数式编程设计模式

8.1 管道模式

class Pipeline<T>(private val value: T) {
    fun <R> pipe(transform: (T) -> R): Pipeline<R> {
        return Pipeline(transform(value))
    }
    
    fun get(): T = value
}

// 扩展函数版本
fun <T> T.pipe(): Pipeline<T> = Pipeline(this)

infix fun <T, R> Pipeline<T>.`|`(transform: (T) -> R): Pipeline<R> {
    return pipe(transform)
}

fun main() {
    val result = " hello world "
        .pipe()
        .pipe { it.trim() }
        .pipe { it.uppercase() }
        .pipe { it.split(" ") }
        .pipe { it.joinToString("-") }
        .get()
    
    println(result)  // HELLO-WORLD
    
    // 使用中缀操作符
    val result2 = "Kotlin" 
        .pipe() 
        | { it.reversed() } 
        | { it.uppercase() }
        | { "Result: $it" }
        .get()
    
    println(result2)  // Result: NILTOK
}

8.2 Option 模式(类似 Optional)

sealed class Option<out T> {
    data class Some<T>(val value: T) : Option<T>()
    object None : Option<Nothing>()
    
    companion object {
        fun <T> of(value: T?): Option<T> {
            return if (value != null) Some(value) else None
        }
    }
    
    fun <R> map(transform: (T) -> R): Option<R> = when (this) {
        is Some -> Some(transform(value))
        None -> None
    }
    
    fun <R> flatMap(transform: (T) -> Option<R>): Option<R> = when (this) {
        is Some -> transform(value)
        None -> None
    }
    
    fun getOrElse(default: () -> T): T = when (this) {
        is Some -> value
        None -> default()
    }
    
    fun orElse(alternative: () -> Option<T>): Option<T> = when (this) {
        is Some -> this
        None -> alternative()
    }
}

// 使用示例
data class User(val name: String, val email: String?)

fun getUserName(userId: Int): Option<User> {
    val users = mapOf(
        1 to User("Alice", "alice@example.com"),
        2 to User("Bob", null)
    )
    return Option.of(users[userId])
}

fun main() {
    val email1 = getUserName(1)
        .flatMap { user -> Option.of(user.email) }
        .getOrElse { "No email" }
    
    val email2 = getUserName(2)
        .flatMap { user -> Option.of(user.email) }
        .getOrElse { "No email" }
    
    println("User 1 email: $email1")  // alice@example.com
    println("User 2 email: $email2")  // No email
}

9. 性能优化

// 1. 使用 inline 减少函数对象开销
inline fun <T> List<T>.fastFilter(predicate: (T) -> Boolean): List<T> {
    val result = mutableListOf<T>()
    for (item in this) {
        if (predicate(item)) {
            result.add(item)
        }
    }
    return result
}

// 2. 使用 sequence 处理大数据集
fun processLargeDataset() {
    val largeList = (1..1_000_000).toList()
    
    // 普通操作(会创建中间集合)
    val result1 = largeList
        .filter { it % 2 == 0 }
        .map { it * 2 }
        .take(1000)
    
    // 序列操作(惰性求值,更高效)
    val result2 = largeList.asSequence()
        .filter { it % 2 == 0 }
        .map { it * 2 }
        .take(1000)
        .toList()
}

// 3. 避免重复计算
fun memoize(function: (Int) -> Int): (Int) -> Int {
    val cache = mutableMapOf<Int, Int>()
    return { input ->
        cache.getOrPut(input) { function(input) }
    }
}

fun expensiveCalculation(n: Int): Int {
    Thread.sleep(100)  // 模拟耗时计算
    return n * n
}

fun main() {
    val memoizedCalc = memoize(::expensiveCalculation)
    
    println(memoizedCalc(5))  // 第一次计算,耗时
    println(memoizedCalc(5))  // 从缓存读取,快速
}

10. 实战案例

10.1 数据转换管道

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

fun main() {
    val people = listOf(
        Person("Alice", 25, "New York"),
        Person("Bob", 30, "London"),
        Person("Charlie", 28, "New York"),
        Person("David", 35, "Paris"),
        Person("Eve", 22, "London")
    )
    
    val result = people
        .filter { it.age > 25 }
        .groupBy { it.city }
        .mapValues { (_, peopleInCity) -> 
            peopleInCity
                .sortedByDescending { it.age }
                .map { it.name }
                .take(2)
        }
        .filter { (_, names) -> names.size >= 2 }
    
    println(result)
    // {New York=[Charlie, Alice], London=[Bob, Eve]}
}

10.2 函数式配置构建器

class DatabaseConfig(
    val url: String,
    val username: String,
    val password: String,
    val poolSize: Int
) {
    data class Builder(
        var url: String = "",
        var username: String = "",
        var password: String = "",
        var poolSize: Int = 10
    ) {
        fun build(): DatabaseConfig {
            require(url.isNotBlank()) { "URL is required" }
            require(username.isNotBlank()) { "Username is required" }
            require(password.isNotBlank()) { "Password is required" }
            require(poolSize > 0) { "Pool size must be positive" }
            
            return DatabaseConfig(url, username, password, poolSize)
        }
    }
}

// 使用 DSL 风格的构建器
fun databaseConfig(configure: DatabaseConfig.Builder.() -> Unit): DatabaseConfig {
    val builder = DatabaseConfig.Builder()
    builder.configure()
    return builder.build()
}

fun main() {
    val config = databaseConfig {
        url = "jdbc:mysql://localhost:3306/mydb"
        username = "admin"
        password = "secret"
        poolSize = 20
    }
    
    println("Connected to ${config.url}")
}

总结

Kotlin 函数式编程优势:

  1. 简洁性 - 减少样板代码
  2. 表达力 - 代码更接近业务逻辑
  3. 安全性 - 不可变性减少副作用
  4. 可测试性 - 纯函数易于测试
  5. 并发友好 - 不可变数据减少竞态条件

最佳实践:

  1. 优先使用不可变数据
  2. 使用标准库函数式操作
  3. 对于大数据集使用 Sequence
  4. 合理使用 inline 优化性能
  5. 结合面向对象和函数式编程的优势

Kotlin 的函数式编程特性让你能够编写更简洁、更安全、更易维护的代码,同时保持与 Java 的完全互操作性。