How to control flow in Kotlin
if
The if statement allows to execute code based on the evaluation of one or more conditions.
In Kotlin if can be an expression that returns last value of <then_block> or <else_block>. Therefore, there is no ternary operator cond?then:else .
else block is required when if is used as expression.
// full syntax
// if(<cond>) {<then_block>} else <else_block>
var max: Int
if (a > b) {
max = a
} else {
max = b
}
// as expression
val max = if (a > b) a else b
when(x)
The when keyword defines a conditional expression with multiple branches. It matches its argument against all branches sequentially until some branch condition is satisfied.
In Kotlin when can be used as an expression that returns last value in the corresponding branch.
The else branch is evaluated if none of the other branch conditions are satisfied.
Unlike switch in Java, you can use arbitrary expressions (not only constants) as branch conditions.
when (x) {
1 -> print("x == 1")
2, 3 -> print("x is 2 or 3")
in 20..30 -> print("x is in the range 20..30")
in validNumbers -> print("x is valid")
!in 40..50 -> print("x is outside the range 40..50")
else -> print("none of the above")
}
You can use is or !is operators
fun hasPrefix(x: Any) = when(x) {
is String -> x.startsWith("prefix")
else -> false
}
You can capture when subject in a variable using following syntax:
fun Request.getBody() =
when (val response = executeRequest()) {
is Success -> response.body
is HttpError -> throw HttpException(response.status)
}
when
If no argument is supplied to the when, the branch conditions are simply boolean expressions, and a branch is executed when its condition is true.
when {
x.isOdd() -> print("x is odd")
x.isEven() -> print("y is even")
else -> print("x+y is odd")
}
for each
The for loop iterates through anything that provides an iterator. This means that it:
- has a member or an extension-function iterator() and the return type of iterator():
- has a member or an extension-function next()
- has a member or an extension-function hasNext() that returns Boolean
All of these three functions need to be marked as operator.
for (item in iterable) {
print(item)
}
For collections you can use the forEach method.
You can iterate through an array or a list with an index:
for (i in array.indices) {
println(array[i])
}
Alternatively, you can use the withIndex() function:
for ((index, value) in array.withIndex()) {
println("the element at $index is $value")
}
for
You can iterate over range of numbers, in this case iterator not used.
for (i in 1..3) { // i in [1..3]
println(i)
}
for (i until 1..3) { // i in [1..3)
println(i)
}
for (i in 6 downTo 0 step 2) { // i: 6,4,2,0
println(i)
}
while
while checks the condition and, if it's satisfied, executes the body.
// full syntax
// while(<cond>){
// <body>
//}
while (x > 0) {
x--
}
do-while
do-while executes the body and then checks the condition. If it's satisfies, the loop repeats.
// full syntax
// do{
// <body>
//} while(<cond>)
do {
val y = retrieveData()
} while (y != null) // y is visible here!
labels
Any expression in Kotlin may be marked with a label. Labels have the form of an identifier followed by the @ sign, for example: abc@.
To label an expression, just add a label in front of it.
loop@ for (i in 1..100) {
// ...
}
break
The break keyword allows to terminate the nearest enclosing loop.
In case of nested loops, you can use labels to terminate the specified loop.
loop@ for (i in 1..100) {
for (j in 1..100) {
if (...) break@loop
}
}
continue
The continue keyword allows to proceed to the next step of the nearest enclosing loop.
In case of nested loops, you can use labels to proceed the specified loop.
loop@ for (i in 1..100) {
for (j in 1..100) {
if (...) continue@loop
}
}
return
By default return returns from the nearest enclosing function or anonymous function (but not lambdas).
You can specify a label to exit from labeled expression.
fun foo() {
listOf(1, 2, 3, 4, 5).forEach {
if (it == 3) return // non-local return directly to the caller of foo()
print(it)
}
println("this point is unreachable")
}
fun foo() {
listOf(1, 2, 3, 4, 5).forEach {
// local return to the caller of the lambda - the forEach loop
// @forEach is default label
if (it == 3) return@forEach
print(it)
}
print(" done with implicit label")
}
fun foo() {
listOf(1, 2, 3, 4, 5).forEach lit@{
// local return to the caller of the lambda - the forEach loop
if (it == 3) return@lit
print(it)
}
print(" done with explicit label")
}