- Android Development with Kotlin
- Marcin Moskala Igor Wojda
- 854字
- 2021-07-02 18:48:38
The when expression
The when expression in Kotlin is a multiway branch statement. The when expression is designed as a more powerful replacement for the Java switch... case statement. The when statement often provides a better alternative than a large series of if... else if statements, as it provides more concise syntax. Let's look at an example:
when (x) { 1 -> print("x == 1") 2 -> print("x == 2") else -> println("x is neither 1 nor 2") }
The when expression matches its argument against all branches one after another until the condition of some branch is satisfied. This behavior is similar to Java's switch... case, but we do not have to write a redundant break statement after every branch.
Similar to the if clause, we can use when either as a statement ignoring the returned value or as an expression and assign its value to a variable. If when is used as an expression, the value of the last line of the satisfied branch becomes the value of the overall expression. If it is used as a statement, the value is simply ignored. As usual, the else branch is evaluated if none of the previous branches satisfy the condition:
val vehicle = "Bike" val message= when (vehicle) { "Car" -> { // Some code "Four wheels" } "Bike" -> { // Some code "Two wheels" } else -> { //some code "Unknown number of wheels" } } println(message) //Prints: Two wheels
Each time a branch has more than one instruction, we must place it inside the code block, defined by two braces {... }. If when is treated as an expression (the result of evaluating when is assigned to a variable), the last line of each block is treated as the return value. We have seen the same behavior with an if expression, so by now you have probably figured out that this is common behavior across many Kotlin constructs, including lambdas, which will be discussed further later in the book.
If when is used as an expression, the else branch is mandatory, unless the compiler can prove that all possible cases are covered with branch conditions. We can also handle many matching arguments in a single branch using commas to separate them:
val vehicle = "Car" when (vehicle) { "Car", "Bike" -> print("Vehicle") else -> print("Unidentified funny object") }
Another nice feature of when is the ability to check variable type. We can easily validate that a value is or !is of a particular type. Smart casts become handy again, because we can access the methods and properties of a matching type in a branch block without any extra checks:
val name = when (person) { is String -> person.toUpperCase() is User -> person.name
//Code is smart casted to String, so we can
//call String class methods
//...
}
In a similar way, we can check which range or collection contains a particular value. This time, we'll use the is and !is keywords:
val riskAssessment = 47 val risk = when (riskAssessment) { in 1..20 -> "negligible risk" !in 21..40 -> "minor risk" !in 41..60 -> "major risk" else -> "undefined risk" } println(risk) // Prints: major risk
Actually, we can put any kind of expression on the right-hand side of the when branch. It can be a method call or any other expression. Consider the following example where the second when expression is used for the else statement:
val riskAssessment = 80 val handleStrategy = "Warn" val risk = when (riskAssessment) { in 1..20 -> print("negligible risk") !in 21..40 -> print("minor risk") !in 41..60 -> print("major risk") else -> when (handleStrategy){ "Warn" -> "Risk assessment warning" "Ignore" -> "Risk ignored" else -> "Unknown risk!" } } println(risk) // Prints: Risk assessment warning
As we can see, when is a very powerful construct, allowing more control than Java's switch, but it is even more powerful because it is not limited only to checking values for equality. In a way, it can even be used as a replacement for an if... else if chain. If no argument is supplied to the when expression, the branch conditions behave as Boolean expressions, and a branch is executed when its condition is true:
private fun getPasswordErrorId(password: String) = when { password.isEmpty() -> R.string.error_field_required passwordInvalid(password) -> R.string.error_invalid_password else -> null }
All the presented examples require an else branch. Each time when all the possible cases are covered, we can omit an else branch (exhaustive when). Let's look at the simplest example with Boolean:
val large:Boolean = true when(large){ true -> println("Big") false -> println("Big") }
The compiler can verify that all possible values are handled, so there is no need to specify an else branch. The same logic applies to enums and sealed classes, which will be discussed in Chapter 4, Classes and Objects.
Checks are performed by the Kotlin compiler, so we have certainty that any case will not be missed. This reduces the possibility of a common Java bug where the developer forgets to handle all the cases inside the switch statement (although polymorphism is usually a better solution).
- 深入淺出Windows API程序設計:編程基礎篇
- 精通API架構:設計、運維與演進
- Learn React with TypeScript 3
- 微服務從小白到專家:Spring Cloud和Kubernetes實戰
- HTML5開發精要與實例詳解
- Mastering AWS Security
- HTML5+CSS3+JavaScript 從入門到項目實踐(超值版)
- 分布式架構原理與實踐
- 前端架構設計
- WCF全面解析
- 自己動手構建編程語言:如何設計編譯器、解釋器和DSL
- JBoss AS 7 Development
- 大話代碼架構:項目實戰版
- Mastering JavaScript Promises
- Java核心技術速學版(第3版)