【Kotlin系列03】控制流与函数:从if表达式到Lambda的进化之路

引言:那个让我重写整个if-else的when表达式

2023年,我在重构一个支付系统的状态处理代码。原本有一个30行的if-else链条:

java 复制代码
// Java:臃肿的if-else
if (status.equals("PENDING")) {
    return "等待支付";
} else if (status.equals("PROCESSING")) {
    return "处理中";
} else if (status.equals("SUCCESS")) {
    return "支付成功";
} else if (status.equals("FAILED")) {
    return "支付失败";
} else if (status.equals("CANCELLED")) {
    return "已取消";
} else if (status.equals("REFUNDED")) {
    return "已退款";
} else {
    return "未知状态";
}

代码审查时,同事说:"你知道Kotlin的when表达式吗?"

5分钟后,代码变成了这样:

kotlin 复制代码
// Kotlin:优雅的when表达式
val statusText = when (status) {
    "PENDING" -> "等待支付"
    "PROCESSING" -> "处理中"
    "SUCCESS" -> "支付成功"
    "FAILED" -> "支付失败"
    "CANCELLED" -> "已取消"
    "REFUNDED" -> "已退款"
    else -> "未知状态"
}

那一刻我意识到:Kotlin不只是Java的简化版,它是对编程范式的重新思考。

今天这篇文章,我们将学习Kotlin的控制流和函数,看看它如何让代码更简洁、更表达性。

if:不是语句,是表达式

Java的if是语句

在Java中,if是语句(statement),不返回值:

java 复制代码
// Java
String result;
if (score >= 90) {
    result = "优秀";
} else if (score >= 60) {
    result = "及格";
} else {
    result = "不及格";
}

Kotlin的if是表达式

在Kotlin中,if是表达式(expression),有返回值:

kotlin 复制代码
// Kotlin:if作为表达式
val result = if (score >= 90) {
    "优秀"
} else if (score >= 60) {
    "及格"
} else {
    "不及格"
}

更简洁的单行写法

kotlin 复制代码
val result = if (score >= 90) "优秀" else if (score >= 60) "及格" else "不及格"

// 或者使用when(后面会讲)
val result = when {
    score >= 90 -> "优秀"
    score >= 60 -> "及格"
    else -> "不及格"
}

if表达式的强大之处

1. 直接赋值给变量

kotlin 复制代码
val max = if (a > b) a else b

val message = if (user != null) {
    "Hello, ${user.name}"
} else {
    "Hello, Guest"
}

2. 作为函数返回值

kotlin 复制代码
fun getDiscount(vipLevel: Int): Double {
    return if (vipLevel >= 3) 0.8
           else if (vipLevel >= 2) 0.9
           else 1.0
}

// 更简洁(单表达式函数)
fun getDiscount(vipLevel: Int) = if (vipLevel >= 3) 0.8 else if (vipLevel >= 2) 0.9 else 1.0

3. 在表达式中使用

kotlin 复制代码
println("You are ${if (age >= 18) "adult" else "minor"}")

val price = basePrice * if (isMember) 0.9 else 1.0

**表达式 vs 语句**: - **表达式(Expression)**:有返回值,如`if`、`when`、`try` - **语句(Statement)**:无返回值,如Java的`if`、`for`

Kotlin将很多传统的"语句"设计成"表达式",让代码更简洁、更函数式。

when:强大的模式匹配

when是Kotlin最强大的控制流特性之一,相当于Java的switch,但功能强大得多。

基本用法

kotlin 复制代码
val dayName = when (dayOfWeek) {
    1 -> "星期一"
    2 -> "星期二"
    3 -> "星期三"
    4 -> "星期四"
    5 -> "星期五"
    6 -> "星期六"
    7 -> "星期日"
    else -> "无效的星期"
}

相比Java的switch优势

  1. ✅ 不需要break(自动break)
  2. ✅ 可以返回值(是表达式)
  3. ✅ 支持任意类型(不限于int、String、enum)
  4. ✅ 支持复杂条件

多值匹配

kotlin 复制代码
val isWeekend = when (dayOfWeek) {
    6, 7 -> true  // 周六或周日
    else -> false
}

val season = when (month) {
    3, 4, 5 -> "春季"
    6, 7, 8 -> "夏季"
    9, 10, 11 -> "秋季"
    12, 1, 2 -> "冬季"
    else -> "无效月份"
}

范围匹配

kotlin 复制代码
val ageGroup = when (age) {
    in 0..12 -> "儿童"
    in 13..17 -> "青少年"
    in 18..59 -> "成年人"
    in 60..Int.MAX_VALUE -> "老年人"
    else -> "无效年龄"
}

val grade = when (score) {
    in 90..100 -> "A"
    in 80..89 -> "B"
    in 70..79 -> "C"
    in 60..69 -> "D"
    else -> "F"
}

类型检查

kotlin 复制代码
fun describe(obj: Any): String = when (obj) {
    is String -> "String of length ${obj.length}"
    is Int -> "Integer: $obj"
    is List<*> -> "List of size ${obj.size}"
    is Boolean -> "Boolean: $obj"
    else -> "Unknown type"
}

// 智能类型转换
val result = when (value) {
    is String -> value.uppercase()  // value自动转为String
    is Int -> value * 2              // value自动转为Int
    else -> "Unknown"
}

无参数when(条件表达式)

最灵活的形式,类似if-else链:

kotlin 复制代码
val healthStatus = when {
    temperature > 38.5 -> "发烧"
    temperature > 37.5 -> "低烧"
    temperature >= 36.0 -> "正常"
    else -> "体温过低"
}

val recommendation = when {
    age < 18 -> "建议家长陪同"
    age >= 65 -> "建议体检"
    hasChronicDisease -> "请咨询医生"
    else -> "可以独立出行"
}

when的高级用法

1. 作为语句(执行多条指令)

kotlin 复制代码
when (command) {
    "start" -> {
        println("Starting service...")
        serviceManager.start()
        println("Service started")
    }
    "stop" -> {
        println("Stopping service...")
        serviceManager.stop()
        println("Service stopped")
    }
    else -> println("Unknown command")
}

2. 替代多个if-else

kotlin 复制代码
// ❌ 不好:多个if-else
if (user.isVip) {
    showVipContent()
} else if (user.isPremium) {
    showPremiumContent()
} else if (user.isRegistered) {
    showRegisteredContent()
} else {
    showGuestContent()
}

// ✅ 好:使用when
when {
    user.isVip -> showVipContent()
    user.isPremium -> showPremiumContent()
    user.isRegistered -> showRegisteredContent()
    else -> showGuestContent()
}

3. 枚举类匹配

kotlin 复制代码
enum class PaymentStatus { PENDING, SUCCESS, FAILED, CANCELLED }

fun handlePayment(status: PaymentStatus) = when (status) {
    PaymentStatus.PENDING -> "等待支付"
    PaymentStatus.SUCCESS -> "支付成功"
    PaymentStatus.FAILED -> "支付失败"
    PaymentStatus.CANCELLED -> "已取消"
    // 注意:枚举类完全覆盖后,不需要else分支
}

循环:for和while

for循环

Kotlin的for循环比Java更灵活,支持多种迭代方式。

1. 遍历范围

kotlin 复制代码
// 1到10(包含10)
for (i in 1..10) {
    println(i)
}

// 1到9(不包含10)
for (i in 1 until 10) {
    println(i)
}

// 10到1(倒序)
for (i in 10 downTo 1) {
    println(i)
}

// 步长为2
for (i in 1..10 step 2) {
    println(i)  // 1, 3, 5, 7, 9
}

2. 遍历集合

kotlin 复制代码
val fruits = listOf("Apple", "Banana", "Cherry")

// 遍历元素
for (fruit in fruits) {
    println(fruit)
}

// 遍历索引
for (i in fruits.indices) {
    println("$i: ${fruits[i]}")
}

// 同时遍历索引和元素
for ((index, fruit) in fruits.withIndex()) {
    println("$index: $fruit")
}

3. 遍历Map

kotlin 复制代码
val map = mapOf("a" to 1, "b" to 2, "c" to 3)

for ((key, value) in map) {
    println("$key -> $value")
}

4. 遍历字符串

kotlin 复制代码
val text = "Kotlin"

for (char in text) {
    println(char)
}

while和do-while

kotlin 复制代码
// while循环
var count = 0
while (count < 5) {
    println("Count: $count")
    count++
}

// do-while循环(至少执行一次)
var input: String
do {
    print("Enter 'yes' to continue: ")
    input = readLine() ?: ""
} while (input != "yes")

循环控制

kotlin 复制代码
// break:跳出循环
for (i in 1..10) {
    if (i == 5) break
    println(i)  // 1, 2, 3, 4
}

// continue:跳过当前迭代
for (i in 1..10) {
    if (i % 2 == 0) continue  // 跳过偶数
    println(i)  // 1, 3, 5, 7, 9
}

// 标签(Label):跳出嵌套循环
loop@ for (i in 1..3) {
    for (j in 1..3) {
        if (i == 2 && j == 2) break@loop
        println("$i, $j")
    }
}

**性能提示**:对于大量数据的处理,考虑使用`forEach`、`map`、`filter`等集合操作符(第5篇会详细讲解),它们更简洁且性能更好。

函数基础

函数定义

kotlin 复制代码
// 基本函数
fun greet(name: String): String {
    return "Hello, $name!"
}

// 单表达式函数(自动推断返回类型)
fun greet(name: String) = "Hello, $name!"

// 无返回值函数(返回Unit,类似Java的void)
fun printGreeting(name: String) {
    println("Hello, $name!")
}

// Unit可以省略
fun printGreeting(name: String): Unit {
    println("Hello, $name!")
}

参数与返回值

1. 默认参数

kotlin 复制代码
// Java需要方法重载
public void connect(String host) {
    connect(host, 8080, 3000);
}
public void connect(String host, int port) {
    connect(host, port, 3000);
}
public void connect(String host, int port, int timeout) {
    // 实际逻辑
}

// Kotlin只需一个函数
fun connect(host: String, port: Int = 8080, timeout: Int = 3000) {
    println("Connecting to $host:$port with timeout $timeout ms")
}

// 调用
connect("localhost")                 // 使用默认port和timeout
connect("localhost", 9000)           // 使用默认timeout
connect("localhost", 9000, 5000)     // 全部指定

2. 命名参数

kotlin 复制代码
fun createUser(
    name: String,
    email: String,
    age: Int = 0,
    isActive: Boolean = true
) {
    println("User: $name, $email, $age, $isActive")
}

// 使用命名参数(可以任意顺序)
createUser(
    name = "Alice",
    email = "alice@example.com"
)

createUser(
    email = "bob@example.com",
    name = "Bob",
    age = 25
)

createUser(
    name = "Charlie",
    email = "charlie@example.com",
    isActive = false
)

**最佳实践**: - 当函数有多个相同类型的参数时,使用命名参数提高可读性 - 当只想指定部分默认参数时,使用命名参数跳过前面的参数

3. 可变参数(vararg)

kotlin 复制代码
fun sum(vararg numbers: Int): Int {
    var result = 0
    for (num in numbers) {
        result += num
    }
    return result
}

// 调用
println(sum(1, 2, 3))        // 6
println(sum(1, 2, 3, 4, 5))  // 15

// 展开数组
val array = intArrayOf(1, 2, 3)
println(sum(*array))  // * 是展开操作符

函数返回值

1. 返回多个值(使用Pair/Triple)

kotlin 复制代码
fun getMinMax(numbers: List<Int>): Pair<Int, Int> {
    return Pair(numbers.minOrNull() ?: 0, numbers.maxOrNull() ?: 0)
}

// 解构赋值
val (min, max) = getMinMax(listOf(1, 5, 3, 9, 2))
println("Min: $min, Max: $max")

// 三个值用Triple
fun getUserInfo(): Triple<String, Int, String> {
    return Triple("Alice", 25, "alice@example.com")
}

val (name, age, email) = getUserInfo()

2. 返回null(可空返回类型)

kotlin 复制代码
fun findUser(id: Int): User? {
    return if (id > 0) User(id, "User$id") else null
}

// 使用
val user = findUser(123)
user?.let {
    println("Found user: ${it.name}")
}

3. Nothing类型(永不返回)

kotlin 复制代码
fun fail(message: String): Nothing {
    throw IllegalArgumentException(message)
}

fun validateAge(age: Int) {
    if (age < 0) {
        fail("Age cannot be negative")
    }
    // 编译器知道这里age >= 0
}

Lambda表达式:函数式编程的基石

什么是Lambda

Lambda表达式是匿名函数的简洁写法:

kotlin 复制代码
// 普通函数
fun double(x: Int): Int {
    return x * 2
}

// Lambda表达式
val double: (Int) -> Int = { x -> x * 2 }

// 使用
println(double(5))  // 10

Lambda语法

kotlin 复制代码
// 完整语法
val sum: (Int, Int) -> Int = { a, b -> a + b }

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

// 多行Lambda
val complexCalc: (Int) -> Int = { x ->
    val temp = x * 2
    temp + 10
}

// 无参数Lambda
val greet: () -> String = { "Hello!" }

Lambda作为参数

kotlin 复制代码
// 高阶函数:接受函数作为参数
fun repeat(times: Int, action: (Int) -> Unit) {
    for (i in 1..times) {
        action(i)
    }
}

// 调用
repeat(3) { index ->
    println("Iteration $index")
}

// 实际应用
val numbers = listOf(1, 2, 3, 4, 5)

// filter:过滤元素
val evenNumbers = numbers.filter { it % 2 == 0 }
println(evenNumbers)  // [2, 4]

// map:转换元素
val doubled = numbers.map { it * 2 }
println(doubled)  // [2, 4, 6, 8, 10]

// forEach:遍历
numbers.forEach { println(it) }

Lambda的简化规则

Kotlin有一套Lambda简化规则,让代码更简洁:

kotlin 复制代码
// 1. 如果Lambda是函数的最后一个参数,可以移到括号外
repeat(3, { index -> println(index) })
repeat(3) { index -> println(index) }  // ✅ 更简洁

// 2. 如果Lambda是唯一参数,括号可以省略
listOf(1, 2, 3).forEach({ println(it) })
listOf(1, 2, 3).forEach { println(it) }  // ✅ 更简洁

// 3. 单参数Lambda可以用it
listOf(1, 2, 3).filter { number -> number % 2 == 0 }
listOf(1, 2, 3).filter { it % 2 == 0 }  // ✅ 更简洁

// 4. 不使用的参数可以用下划线
val map = mapOf("a" to 1, "b" to 2)
map.forEach { (key, _) -> println(key) }  // 只用key,忽略value

函数引用

有时候已经有一个函数,不想重复写Lambda:

kotlin 复制代码
fun isEven(number: Int): Boolean {
    return number % 2 == 0
}

// 使用Lambda
val evenNumbers1 = numbers.filter { isEven(it) }

// 使用函数引用(::)
val evenNumbers2 = numbers.filter(::isEven)  // ✅ 更简洁

// 成员函数引用
val lengths = listOf("a", "bb", "ccc").map(String::length)
println(lengths)  // [1, 2, 3]

实战:构建一个灵活的计算器

让我们综合运用本文所学知识,构建一个支持多种运算的计算器:

kotlin 复制代码
// 定义运算类型
enum class Operation {
    ADD, SUBTRACT, MULTIPLY, DIVIDE, POWER, MODULO
}

class Calculator {
    // 使用when表达式选择运算
    fun calculate(a: Double, b: Double, operation: Operation): Double {
        return when (operation) {
            Operation.ADD -> a + b
            Operation.SUBTRACT -> a - b
            Operation.MULTIPLY -> a * b
            Operation.DIVIDE -> {
                if (b == 0.0) throw IllegalArgumentException("除数不能为0")
                a / b
            }
            Operation.POWER -> Math.pow(a, b)
            Operation.MODULO -> a % b
        }
    }

    // 使用Lambda实现自定义运算
    fun calculateCustom(a: Double, b: Double, operation: (Double, Double) -> Double): Double {
        return operation(a, b)
    }

    // 批量计算(vararg + Lambda)
    fun batchCalculate(
        vararg values: Double,
        operation: (Double, Double) -> Double
    ): Double {
        if (values.isEmpty()) return 0.0

        var result = values[0]
        for (i in 1 until values.size) {
            result = operation(result, values[i])
        }
        return result
    }

    // 条件计算(if表达式)
    fun calculateWithTax(
        amount: Double,
        includesTax: Boolean = false,
        taxRate: Double = 0.1
    ): Double {
        return if (includesTax) {
            amount
        } else {
            amount * (1 + taxRate)
        }
    }
}

// 使用示例
fun main() {
    val calc = Calculator()

    // 1. 基本运算(when表达式)
    println("10 + 5 = ${calc.calculate(10.0, 5.0, Operation.ADD)}")
    println("10 - 5 = ${calc.calculate(10.0, 5.0, Operation.SUBTRACT)}")
    println("10 * 5 = ${calc.calculate(10.0, 5.0, Operation.MULTIPLY)}")
    println("10 / 5 = ${calc.calculate(10.0, 5.0, Operation.DIVIDE)}")

    // 2. 自定义运算(Lambda)
    val avg = calc.calculateCustom(10.0, 20.0) { a, b -> (a + b) / 2 }
    println("Average: $avg")  // 15.0

    val max = calc.calculateCustom(10.0, 20.0) { a, b ->
        if (a > b) a else b
    }
    println("Max: $max")  // 20.0

    // 3. 批量计算
    val sum = calc.batchCalculate(1.0, 2.0, 3.0, 4.0, 5.0) { a, b -> a + b }
    println("Sum: $sum")  // 15.0

    val product = calc.batchCalculate(2.0, 3.0, 4.0) { a, b -> a * b }
    println("Product: $product")  // 24.0

    // 4. 条件计算(默认参数 + 命名参数)
    println("不含税: ${calc.calculateWithTax(100.0)}")  // 110.0
    println("含税: ${calc.calculateWithTax(100.0, includesTax = true)}")  // 100.0
    println("自定义税率: ${calc.calculateWithTax(100.0, taxRate = 0.15)}")  // 115.0

    // 5. 链式计算(函数引用)
    val numbers = listOf(1.0, 2.0, 3.0, 4.0, 5.0)
    val sumUsingFilter = numbers
        .filter { it > 2.0 }  // [3.0, 4.0, 5.0]
        .map { it * 2 }       // [6.0, 8.0, 10.0]
        .reduce { acc, value -> acc + value }  // 24.0
    println("Filtered sum: $sumUsingFilter")
}

代码亮点分析:

  1. when表达式:简洁的运算类型选择
  2. Lambda参数:支持自定义运算逻辑
  3. 默认参数 + 命名参数:灵活的函数调用
  4. vararg:支持任意数量的参数
  5. 高阶函数:函数作为参数传递
  6. 链式调用filtermapreduce

常见问题

Q1: if表达式必须有else吗?

kotlin 复制代码
// 作为表达式时,必须有else
val result = if (condition) "yes" else "no"  // ✅

// 编译错误:缺少else
// val result = if (condition) "yes"  // ❌

// 作为语句时,可以没有else
if (condition) {
    println("yes")
}  // ✅

Q2: when什么时候需要else?

kotlin 复制代码
// 1. 作为表达式时,如果未穷尽所有可能,需要else
val result = when (value) {
    1 -> "one"
    2 -> "two"
    else -> "other"  // 必须有else
}

// 2. 枚举类型穷尽所有情况时,不需要else
enum class Color { RED, GREEN, BLUE }

val colorName = when (color) {
    Color.RED -> "红色"
    Color.GREEN -> "绿色"
    Color.BLUE -> "蓝色"
    // 不需要else,已穷尽
}

// 3. 作为语句时,可以没有else
when (command) {
    "start" -> start()
    "stop" -> stop()
    // 不需要else
}

Q3: Lambda里的return会返回什么?

kotlin 复制代码
fun example() {
    val numbers = listOf(1, 2, 3, 4, 5)

    // 错误:return会退出example函数,不是退出Lambda
    numbers.forEach {
        if (it == 3) return  // 退出example函数!
        println(it)
    }
    println("This won't print if 3 is in list")
}

// 正确:使用return@forEach标签返回Lambda
fun example2() {
    val numbers = listOf(1, 2, 3, 4, 5)

    numbers.forEach {
        if (it == 3) return@forEach  // 只退出当前Lambda
        println(it)
    }
    println("This will always print")  // 输出:1 2 4 5 This will always print
}

Q4: 什么时候用for,什么时候用forEach?

场景 推荐 原因
简单遍历 forEach 更简洁,函数式风格
需要break/continue for forEach不支持break
需要索引 forEachIndexedfor 都可以,看个人喜好
性能关键 for 避免Lambda开销
链式操作 集合操作符 mapfilter
kotlin 复制代码
// forEach:简洁
numbers.forEach { println(it) }

// for:需要break
for (num in numbers) {
    if (num > 5) break
    println(num)
}

// forEachIndexed:需要索引
numbers.forEachIndexed { index, value ->
    println("$index: $value")
}

总结

今天我们学习了Kotlin控制流和函数的核心知识:

  1. if表达式:不仅是语句,更是表达式,有返回值
  2. when表达式:强大的模式匹配,支持多值、范围、类型检查
  3. for循环:灵活的迭代方式,支持范围、集合、步长
  4. 函数:默认参数、命名参数、可变参数,让函数调用更灵活
  5. Lambda表达式:匿名函数的简洁写法,函数式编程的基石
  6. 高阶函数:函数作为参数,实现更灵活的代码

最重要的收获 :Kotlin的控制流不是简单的语法糖,而是将表达式思维融入语言设计。这让代码更简洁、更表达性、更函数式。

下一篇文章,我们将学习类与对象基础,包括类定义、构造函数、属性、数据类等。这将让你开始面向对象编程的Kotlin之旅。

练习题

巩固今天的知识,尝试完成以下练习:

  1. when表达式练习
kotlin 复制代码
// 实现一个函数,根据HTTP状态码返回描述
fun getHttpStatusDescription(code: Int): String {
    // 使用when表达式实现
    // 200 -> "OK"
    // 201 -> "Created"
    // 400 -> "Bad Request"
    // 401 -> "Unauthorized"
    // 404 -> "Not Found"
    // 500 -> "Internal Server Error"
    // 其他 -> "Unknown Status"
}
  1. Lambda练习
kotlin 复制代码
// 实现一个高阶函数,对列表进行条件过滤和转换
fun transformList(
    numbers: List<Int>,
    filter: (Int) -> Boolean,
    transform: (Int) -> Int
): List<Int> {
    // 使用filter和map实现
}

// 使用示例
val result = transformList(
    listOf(1, 2, 3, 4, 5, 6),
    filter = { it % 2 == 0 },  // 只保留偶数
    transform = { it * it }     // 平方
)
// 结果应该是 [4, 16, 36]
  1. 综合练习
kotlin 复制代码
// 实现一个成绩管理系统
data class Student(val name: String, val score: Int)

fun analyzeScores(students: List<Student>) {
    // 1. 统计各等级人数(A: 90+, B: 80-89, C: 70-79, D: 60-69, F: <60)
    // 2. 找出最高分和最低分的学生
    // 3. 计算平均分
    // 4. 输出所有不及格学生的姓名
}

答案在文章评论区,或者你可以在Kotlin Playground中自己尝试!


系列文章导航:


如果这篇文章对你有帮助,欢迎点赞、收藏、分享!有任何问题或建议,欢迎在评论区留言讨论。让我们一起学习,一起成长!

也欢迎访问我的个人主页发现更多宝藏资源

相关推荐
冬奇Lab3 小时前
稳定性性能系列之十二——Android渲染性能深度优化:SurfaceFlinger与GPU
android·性能优化·debug
冬奇Lab4 小时前
稳定性性能系列之十一——Android内存优化与OOM问题深度解决
android·性能优化
用户74589002079546 小时前
线程池
android
专注前端30年6 小时前
【PHP开发与安全防护实战】性能调优手册
android·安全·php
王正南7 小时前
安卓逆向之LSposed开发(一)
android·xposed·lsposed
YIN_尹8 小时前
【MySQL】数据类型(上)
android·mysql·adb
zh_xuan9 小时前
kotlin 类继承的语法
开发语言·kotlin
robotx10 小时前
AOSP设备节点权限添加相关
android