编程Kotlin开发人员

Kotlin中的when结构是什么?它是如何工作的?与Java中的switch-case有何不同,并为处理各种情况提供了哪些功能?请举出各种使用情况的示例。

用 Hintsage AI 助手通过面试

答案。

Kotlin中的when结构是一个强大的工具,用于控制程序的执行流,取代了Java中的传统switch-casewhen的引入旨在提高表达能力,减少样板代码,并提高类型安全性。

问题的历史

在Java中,switch-case结构仅限于某些特定类型(枚举、int、String)。与Java不同,Kotlin的开发者希望简化条件分支,使其更具表达性和安全性。

问题

Java中的switch-case的限制使得代码的扩展和维护变得困难,尤其是在处理集合、比较范围或处理不同类型时。

解决方案

Kotlin中的when结构是通用的:它可以作为表达式工作(可以返回值),支持条件检查、范围、单个值、类型和条件组合。

代码示例:

fun describe(obj: Any): String = when (obj) { 1 -> "One" in 2..10 -> "From two to ten" is String -> "String with length ${obj.length}" else -> "Unknown" } val res1 = describe(1) // "One" val res2 = describe(5) // "From two to ten" val res3 = describe("Kotlin") // "String with length 6" val res4 = describe(42.0) // "Unknown"

关键特性:

  • 可以同时处理表达式和操作符。
  • 根据值、类型、范围和复杂条件进行检查。
  • 确保处理所有情况的安全性(例如,使用密封类)。

带陷阱的问题。

when可以不带参数使用吗?

是的,当不需要检查特定变量的值时,可以将when用作长if-else链的替代。

when { x < 0 -> println("Negative") x == 0 -> println("Zero") else -> println("Positive") }

when结构中的else块是必须的吗?

如果处理了所有可能的情况,比如对于枚举或密封类,则else块不是必需的。但是,如果存在未覆盖情况的可能性,则必须提供else以避免编译时错误。

sealed class Fruit object Apple : Fruit() object Pear : Fruit() fun check(f: Fruit): String = when (f) { Apple -> "It's an apple" Pear -> "It's a pear" // 没有else块,编译器不报错 — 所有情况都已考虑 }

可以在一个分支中使用多个值吗?

是的,可以通过逗号将多个值组合在一起。

when (value) { 0, 1 -> println("Zero or One") else -> println("Other") }

常见错误和反模式

  • 在部分情况中遗漏else块(可能导致运行时错误)。
  • when过于复杂的分支导致可读性下降。
  • 仅仅将when用作switch-case,而不使用类型和范围检查。

生活中的例子

消极案例

在支付系统中,switch-case用于确定操作状态。在添加新状态类型时,忘记更新switch。未处理的状态导致silent-error。

优点:

  • 当状态数量较少时,快速实现更改。

缺点:

  • 没有保证所有状态都得到考虑。
  • 出现新值时的隐性silent错误。

积极案例

在Kotlin中,使用密封类来表示状态,并使用when来处理它们。添加新状态时,编译器要求添加对新情况的处理。

优点:

  • 安全地处理所有状态。
  • 在遗漏案例时,编译错误。

缺点:

  • 在扩展系统时,必须仔细更新密封类。