MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Kotlin控制流程之when表达式

2023-05-015.1k 阅读

when 表达式基础

在 Kotlin 中,when 表达式是一种强大的控制流结构,类似于其他语言中的 switch - case 语句,但它更加灵活和功能丰富。when 表达式允许根据一个值来选择执行多个分支中的一个。其基本语法如下:

val number = 2
val result = when (number) {
    1 -> "One"
    2 -> "Two"
    3 -> "Three"
    else -> "Other"
}
println(result)

在上述代码中,when 后面的括号中的 number 是被判断的值。when 会依次检查每个分支,当发现匹配的条件时,就会执行对应的代码块,并返回该代码块的值(这里每个分支返回一个字符串)。如果没有匹配的分支,就会执行 else 分支。

when 表达式作为语句

when 也可以作为一个语句来使用,在这种情况下,它不需要返回值。例如:

val dayOfWeek = 3
when (dayOfWeek) {
    1 -> println("Monday")
    2 -> println("Tuesday")
    3 -> println("Wednesday")
    4 -> println("Thursday")
    5 -> println("Friday")
    6 -> println("Saturday")
    7 -> println("Sunday")
    else -> println("Invalid day")
}

在这个例子中,when 根据 dayOfWeek 的值来打印相应的星期几。每个分支只是执行一个 println 语句,而不是返回一个值。

匹配多个值

when 表达式允许在一个分支中匹配多个值。可以使用逗号来分隔多个值。例如:

val number = 3
val result = when (number) {
    1, 2 -> "Small number"
    3, 4 -> "Medium number"
    else -> "Large number"
}
println(result)

这里 number 的值为 3,它匹配 3, 4 这个分支,所以会输出 Medium number

范围匹配

when 可以使用范围来进行匹配。Kotlin 中的范围使用 .. 操作符来定义。例如:

val age = 25
val result = when (age) {
    in 0..12 -> "Child"
    in 13..19 -> "Teenager"
    in 20..64 -> "Adult"
    else -> "Senior"
}
println(result)

在这个例子中,age 的值为 25,它在 20..64 这个范围内,所以会输出 Adult。如果要检查值是否不在某个范围内,可以使用 !in。例如:

val number = 15
val result = when (number) {
    !in 1..10 -> "Outside the range 1 - 10"
    else -> "Inside the range 1 - 10"
}
println(result)

这里 number15,不在 1..10 范围内,所以会输出 Outside the range 1 - 10

类型匹配

when 还可以用于类型匹配,这在处理泛型或者需要根据对象类型进行不同操作时非常有用。例如:

fun printType(obj: Any) {
    when (obj) {
        is String -> println("It's a string: $obj")
        is Int -> println("It's an integer: $obj")
        is Double -> println("It's a double: $obj")
        else -> println("Unknown type")
    }
}

printType("Hello")
printType(10)
printType(3.14)
printType(true)

printType 函数中,when 根据 obj 的类型来执行不同的分支。is 关键字用于检查对象是否是某个类型。如果对象是指定类型,when 会执行相应的代码块。在这个例子中,分别传入了字符串、整数、双精度浮点数和布尔值,when 会根据类型打印相应的信息。

无参数的 when

when 表达式不一定需要在括号中传入值。在这种情况下,它会检查每个分支的条件是否为真。例如:

val x = 10
val y = 20
val result = when {
    x > y -> "x is greater than y"
    x < y -> "x is less than y"
    else -> "x is equal to y"
}
println(result)

这里 when 没有参数,每个分支都是一个布尔表达式。x < y 为真,所以会输出 x is less than y

when 表达式的返回值

when 表达式是有返回值的,其返回值是最后执行分支的值。例如:

fun getGrade(score: Int): String {
    return when (score) {
        in 90..100 -> "A"
        in 80..89 -> "B"
        in 70..79 -> "C"
        in 60..69 -> "D"
        else -> "F"
    }
}

val score = 85
val grade = getGrade(score)
println("The grade is $grade")

getGrade 函数中,when 根据 score 的值返回相应的等级。这里 score85,匹配 in 80..89 分支,所以返回 B

when 表达式的嵌套

when 表达式可以嵌套使用,以实现更复杂的逻辑。例如:

val season = "Summer"
val day = "Sunday"
val activity = when (season) {
    "Summer" -> when (day) {
        "Saturday", "Sunday" -> "Go to the beach"
        else -> "Work"
    }
    "Winter" -> when (day) {
        "Saturday", "Sunday" -> "Go skiing"
        else -> "Work"
    }
    else -> "Stay at home"
}
println(activity)

在这个例子中,外层的 when 根据 season 的值进行判断,内层的 when 再根据 day 的值进一步判断,最终返回合适的活动。这里 seasonSummerdaySunday,所以会输出 Go to the beach

when 表达式与集合匹配

when 可以与集合进行匹配,检查某个值是否在集合中。例如:

val fruits = listOf("Apple", "Banana", "Cherry")
val fruit = "Banana"
val result = when (fruit) {
    in fruits -> "Fruit is in the list"
    else -> "Fruit is not in the list"
}
println(result)

这里 fruit 的值为 Banana,它在 fruits 列表中,所以会输出 Fruit is in the list

when 表达式在循环中的使用

虽然 when 本身不是专门为循环设计的,但在循环内部可以使用 when 来根据不同条件执行不同操作。例如:

for (i in 1..5) {
    when (i) {
        1 -> println("First")
        2 -> println("Second")
        3 -> println("Third")
        else -> println("Other")
    }
}

在这个 for 循环中,每次迭代都会根据 i 的值执行 when 中的不同分支。

when 表达式的性能优化

在使用 when 表达式时,如果分支很多,特别是在使用大量常量匹配时,可以考虑性能优化。例如,如果分支是基于整数常量的匹配,Kotlin 编译器会优化生成的字节码,使其执行效率更高。但如果是复杂的条件匹配,可能需要考虑其他方式来提高性能。

另外,在使用 when 进行类型匹配时,如果有多个类型分支,尽量将最有可能匹配的类型放在前面,这样可以减少不必要的类型检查,提高性能。

when 表达式在实际项目中的应用

在实际的 Android 开发中,when 表达式经常用于处理用户界面事件。例如,处理按钮点击事件时,可以使用 when 根据不同的按钮 ID 执行不同的操作。

button.setOnClickListener {
    when (it.id) {
        R.id.button1 -> {
            // 执行按钮1的操作
            Toast.makeText(this, "Button 1 clicked", Toast.LENGTH_SHORT).show()
        }
        R.id.button2 -> {
            // 执行按钮2的操作
            Toast.makeText(this, "Button 2 clicked", Toast.LENGTH_SHORT).show()
        }
        else -> {
            // 其他按钮的操作
        }
    }
}

在服务器端开发中,when 也可以用于处理不同的 HTTP 请求类型。例如,在一个基于 Kotlin 的 Web 框架中:

fun handleRequest(request: HttpRequest) {
    when (request.method) {
        HttpMethod.GET -> handleGetRequest(request)
        HttpMethod.POST -> handlePostRequest(request)
        HttpMethod.PUT -> handlePutRequest(request)
        HttpMethod.DELETE -> handleDeleteRequest(request)
        else -> sendErrorResponse(request, "Unsupported method")
    }
}

when 表达式与函数式编程

when 表达式在函数式编程风格中也能很好地融合。它可以与高阶函数一起使用,实现更加灵活和简洁的代码。例如,可以将 when 表达式的结果作为参数传递给其他函数。

fun performAction(action: () -> Unit) {
    action()
}

val number = 5
val action = when (number) {
    1 -> {
        { println("Performing action for 1") }
    }
    5 -> {
        { println("Performing action for 5") }
    }
    else -> {
        { println("Performing default action") }
    }
}
performAction(action)

在这个例子中,when 根据 number 的值返回不同的函数,然后将这个函数传递给 performAction 函数并执行。

when 表达式的局限性

尽管 when 表达式功能强大,但它也有一些局限性。例如,在处理非常复杂的逻辑时,when 可能会变得冗长和难以维护。在这种情况下,可能需要考虑将逻辑拆分成多个函数或者使用其他设计模式。

另外,when 表达式在匹配复杂对象时,如果对象没有合适的 equalshashCode 方法,可能会导致匹配不准确。例如,如果自定义了一个类,并且在 when 中根据对象实例进行匹配,就需要确保该类正确实现了 equalshashCode 方法。

when 表达式与其他语言的对比

与 Java 的 switch - case 语句相比,Kotlin 的 when 表达式更加灵活。Java 的 switch - case 只能用于基本类型(byteshortcharint 及其包装类)和 String 类型,而 Kotlin 的 when 可以用于任何类型,包括自定义类型。

在 Python 中,没有直接与 when 对应的结构,但可以通过 if - elif - else 语句来实现类似的功能。不过,if - elif - else 语句在处理多个条件时通常不如 when 表达式简洁,特别是在匹配常量值或者范围时。

例如,在 Python 中实现类似 when 范围匹配的功能:

age = 25
if 0 <= age <= 12:
    print("Child")
elif 13 <= age <= 19:
    print("Teenager")
elif 20 <= age <= 64:
    print("Adult")
else:
    print("Senior")

与 Kotlin 的 when 相比,Python 的代码看起来更加冗长,并且可读性在一定程度上有所降低。

总结 when 表达式的要点

  1. 基本语法when 表达式根据值选择执行多个分支中的一个,支持多种匹配方式,包括常量值、范围、类型等。
  2. 作为语句和表达式:既可以作为语句执行某些操作,也可以作为表达式返回值。
  3. 匹配方式:支持匹配多个值、范围匹配、类型匹配、无参数匹配以及与集合匹配等多种方式。
  4. 嵌套和循环使用:可以嵌套以实现复杂逻辑,也可以在循环内部使用。
  5. 性能和优化:在处理大量常量匹配时编译器会优化,注意类型匹配顺序以提高性能。
  6. 实际应用:在 Android 开发和服务器端开发等实际项目中有广泛应用。
  7. 与其他语言对比:比 Java 的 switch - case 更灵活,与 Python 的 if - elif - else 相比更简洁。

通过深入理解和灵活运用 when 表达式,Kotlin 开发者能够编写出更加简洁、高效和易读的代码。无论是简单的条件判断还是复杂的业务逻辑处理,when 表达式都能成为强大的工具。