Lambda表达式:让代码会说话

Lambda表达式,说白了就是一段可以到处传递的代码块。我刚开始接触Kotlin时,就被这种写法惊艳到了——原来代码可以写得这么「像人话」。

你想想看,在Java里写个点击监听器,要new一个匿名内部类,啰嗦得很。Kotlin的Lambda,几行就搞定。我个人习惯把Lambda看作「轻量级的函数快递」——把行为打包,送到需要的地方去执行。

Lambda语法:最简形式

Lambda的基本语法长这样:

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

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

// 最简形式
val sum = { x, y -> x + y }

箭头左边是参数,右边是函数体。最后一行表达式就是返回值。嗯,这里要注意:Lambda没有return关键字,最后一行自动返回。

核心要点:Lambda表达式用花括号包裹,参数和函数体用->分隔。如果参数只有一个,可以省略参数声明,直接用it

Lambda作为参数:传递行为

这才是Lambda的真正威力。你可以把一段逻辑当作参数传给另一个函数。我在项目中遇到过很多场景,比如列表过滤、数据转换,用Lambda写起来行云流水。

// 定义一个接受Lambda的函数
fun processNumbers(numbers: List<Int>, operation: (Int) -> Int): List<Int> {
    return numbers.map { operation(it) }
}

// 调用时传入Lambda
val result = processNumbers(listOf(1, 2, 3)) { it * 2 }
println(result) // [2, 4, 6]

为什么会这样?因为Kotlin有个约定:如果Lambda是函数的最后一个参数,可以把它写在括号外面。这就是「尾Lambda语法」。你想想看,这样写出来的代码,读起来就像在说「处理这些数字,每个都乘以2」。

我的习惯:如果Lambda参数很长,我通常会把它单独拎出来,放在括号后面。这样代码结构更清晰,可读性更好。

it关键字:隐式参数

当Lambda只有一个参数时,Kotlin允许你省略参数声明,直接用it来引用它。这玩意儿用起来特别顺手,但也容易让人迷糊。

// 显式参数
val doubled = listOf(1, 2, 3).map { number -> number * 2 }

// 使用it
val doubled = listOf(1, 2, 3).map { it * 2 }

// 多层嵌套时,it会让人困惑
val nested = listOf(1, 2, 3).map { 
    listOf(4, 5, 6).map { 
        // 这里的it指的是内层Lambda的参数
        it + it 
    }
}

我曾经踩过的坑:在嵌套Lambda里滥用it,结果代码读起来像天书。后来我定了个规矩:嵌套超过一层,必须显式命名参数。别偷懒,不然三个月后你自己都看不懂。

Lambda与匿名函数:同根不同命

匿名函数和Lambda很像,但有几个关键区别。我刚开始学的时候也搞混过,后来才摸清楚门道。

特性 Lambda 匿名函数
语法 { x -> x + 1 } fun(x: Int): Int { return x + 1 }
返回值 最后一行自动返回 需要显式return
参数类型 可推断时省略 通常需要声明
使用场景 简短逻辑,一行搞定 复杂逻辑,需要多个return
// Lambda写法
val lambda: (Int) -> Int = { x -> 
    if (x > 0) x * 2 else 0
}

// 匿名函数写法
val anonymous: (Int) -> Int = fun(x: Int): Int {
    if (x > 0) return x * 2
    return 0
}

我个人更偏爱Lambda,因为它简洁。但如果你需要多个return点,或者逻辑比较复杂,匿名函数会更清晰。说白了,选哪个取决于场景——没有银弹。

避坑指南:Lambda里的return行为比较特殊。在Lambda里写return,它会从外层函数返回,而不是只退出Lambda。这就是「非局部返回」。如果你只想退出Lambda,要用标签:return@label。我曾经因为这个bug排查了一下午,印象深刻。

实战:用Lambda重构代码

来看一个真实场景。假设你要处理用户列表,筛选出活跃用户,然后提取他们的名字。

// 传统写法
fun getActiveUserNames(users: List<User>): List<String> {
    val result = mutableListOf<String>()
    for (user in users) {
        if (user.isActive) {
            result.add(user.name)
        }
    }
    return result
}

// Lambda写法
fun getActiveUserNames(users: List<User>): List<String> {
    return users.filter { it.isActive }
                .map { it.name }
}

你想想看,第二种写法是不是像在读英文句子?「过滤出活跃的,然后映射出名字」。这就是Lambda的魅力——让代码从「告诉计算机怎么做」变成「告诉计算机你想要什么」。

嗯,到这里Lambda的基础就讲完了。下一章我们会深入高阶函数,看看Lambda还能玩出什么花样。记住,多写多练,Lambda用顺手了,你会爱上这种表达方式的。