[//]: # (title: Conditions and loops)
Kotlin gives you flexible tools to control your program's flow. Use `if`, `when`, and loops to define clear,
expressive logic for your conditions.
## If expression
To use `if` in Kotlin, add the condition to check within parentheses `()` and the action to take if the result is true
within curly braces `{}`. You can use `else` and `else if` for additional branches and checks.
You can also write `if` as an expression, which lets you assign its returned value directly to a variable.
In this form, an `else` branch is required. The `if` expression serves the same purpose as the ternary operator
(`condition ? then : else`) found in other languages.
For example:
```kotlin
fun main() {
val heightAlice = 160
val heightBob = 175
//sampleStart
var taller = heightAlice
if (heightAlice < heightBob) taller = heightBob
// Uses an else branch
if (heightAlice > heightBob) {
taller = heightAlice
} else {
taller = heightBob
}
// Uses if as an expression
taller = if (heightAlice > heightBob) heightAlice else heightBob
// Uses else if as an expression:
val heightLimit = 150
val heightOrLimit = if (heightLimit > heightAlice) heightLimit else if (heightAlice > heightBob) heightAlice else heightBob
println("Taller height is $taller")
// Taller height is 175
println("Height or limit is $heightOrLimit")
// Height or limit is 175
//sampleEnd
}
```
{kotlin-runnable="true" kotlin-min-compiler-version="1.3" id="if-else-if-kotlin"}
Each branch in an `if` expression can be a block, where the value of the last expression becomes the result:
```kotlin
fun main() {
//sampleStart
val heightAlice = 160
val heightBob = 175
val taller = if (heightAlice > heightBob) {
print("Choose Alice\n")
heightAlice
} else {
print("Choose Bob\n")
heightBob
}
println("Taller height is $taller")
//sampleEnd
}
```
{kotlin-runnable="true" kotlin-min-compiler-version="1.3" id="if-else-blocks-kotlin"}
## When expressions and statements
`when` is a conditional expression that runs code based on multiple possible values or conditions. It's
similar to the `switch` statement in Java, C, and other languages. `when` evaluates its argument and compares the result
against each branch in order until one branch condition is satisfied. For example:
```kotlin
fun main() {
//sampleStart
val userRole = "Editor"
when (userRole) {
"Viewer" -> print("User has read-only access")
"Editor" -> print("User can edit content")
else -> print("User role is not recognized")
}
// User can edit content
//sampleEnd
}
```
{kotlin-runnable="true" kotlin-min-compiler-version="1.3" id="kotlin-conditions-when-statement"}
You can use `when` either as an **expression** or a **statement**. As an expression, `when` returns a value you can use
later in your code. As a statement, `when` completes an action without returning a result:
| Expression |
Statement |
|
```kotlin
// Returns a string assigned to the
// text variable
val text = when (x) {
1 -> "x == 1"
2 -> "x == 2"
else -> "x is neither 1 nor 2"
}
```
|
```kotlin
// Returns no result but triggers a
// print statement
when (x) {
1 -> print("x == 1")
2 -> print("x == 2")
else -> print("x is neither 1 nor 2")
}
```
|
Secondly, you can use `when` with or without a subject. The behavior stays the same either way. Using a subject usually
makes your code more readable and maintainable because it clearly shows what you're checking.
With subject x |
Without subject |
|
```kotlin
when(x) { ... }
```
|
```kotlin
when { ... }
```
|
How you use `when` determines whether you need to cover all possible cases in your branches. Covering all possible cases
is called being _exhaustive_.
### Statements
If you use `when` as a statement, you don't need to cover all possible cases. In this example, some cases aren't covered,
so no branch is triggered. However, no error occurs:
```kotlin
fun main() {
//sampleStart
val deliveryStatus = "OutForDelivery"
when (deliveryStatus) {
// Not all cases are covered
"Pending" -> print("Your order is being prepared")
"Shipped" -> print("Your order is on the way")
}
//sampleEnd
}
```
{kotlin-runnable="true" kotlin-min-compiler-version="1.3" id="kotlin-when-statement"}
Just like with `if`, each branch can be a block, and its value is the value of the last expression in the block.
### Expressions
If you use `when` as an expression, you **must** cover all possible cases. The value of the first matching branch becomes
the value of the overall expression. If you don't cover all cases, the compiler throws an error.
If your `when` expression has a subject, you can use an `else` branch to make sure that all possible cases are covered, but
it isn't mandatory. For example, if your subject is a `Boolean`, [`enum` class](enum-classes.md), [`sealed` class](sealed-classes.md),
or one of their nullable counterparts, you can cover all cases without an `else` branch:
```kotlin
import kotlin.random.Random
//sampleStart
enum class Bit {
ZERO, ONE
}
fun getRandomBit(): Bit {
return if (Random.nextBoolean()) Bit.ONE else Bit.ZERO
}
fun main() {
val numericValue = when (getRandomBit()) {
// No else branch is needed because all cases are covered
Bit.ZERO -> 0
Bit.ONE -> 1
}
println("Random bit as number: $numericValue")
// Random bit as number: 0
//sampleEnd
}
```
{kotlin-runnable="true" kotlin-min-compiler-version="1.3" id="kotlin-when-expression-subject"}
> To simplify `when` expressions and reduce repetition, try out context-sensitive resolution (currently in preview).
> This feature allows you to omit the type name when using enum entries or sealed class members in `when` expressions if the expected type is known.
>
> For more information, see [Preview of context-sensitive resolution](whatsnew22.md#preview-of-context-sensitive-resolution) or the related [KEEP proposal](https://github.com/Kotlin/KEEP/blob/improved-resolution-expected-type/proposals/context-sensitive-resolution.md).
>
{style="tip"}
If your `when` expression **doesn't** have a subject, you **must** have an `else` branch or the compiler throws an error.
The `else` branch is evaluated when none of the other branch conditions are satisfied:
```kotlin
fun main() {
//sampleStart
val localFileSize = 1200
val remoteFileSize = 1200
val message = when {
localFileSize > remoteFileSize -> "Local file is larger than remote file"
localFileSize < remoteFileSize -> "Local file is smaller than remote file"
else -> "Local and remote files are the same size"
}
println(message)
// Local and remote files are the same size
//sampleEnd
}
```
{kotlin-runnable="true" kotlin-min-compiler-version="1.3" id="kotlin-when-no-subject"}
### Other ways to use when
`when` expressions and statements offer different ways to simplify your code, handle multiple conditions, and perform
type checks.
Group multiple conditions into a single branch using commas:
```kotlin
fun main() {
val ticketPriority = "High"
//sampleStart
when (ticketPriority) {
"Low", "Medium" -> print("Standard response time")
else -> print("High-priority handling")
}
//sampleEnd
}
```
{kotlin-runnable="true" kotlin-min-compiler-version="1.3" id="kotlin-when-multiple-cases"}
Use expressions that evaluate to `true` or `false` as branch conditions:
```kotlin
fun main() {
val storedPin = "1234"
val enteredPin = 1234
//sampleStart
when (enteredPin) {
// Expression
storedPin.toInt() -> print("PIN is correct")
else -> print("Incorrect PIN")
}
//sampleEnd
}
```
{kotlin-runnable="true" kotlin-min-compiler-version="1.3" id="kotlin-when-branch-expression"}
Check whether a value is or isn't contained in a [range](ranges.md) or collection using the `in` or `!in` keywords:
```kotlin
fun main() {
val x = 7
val validNumbers = setOf(15, 16, 17)
//sampleStart
when (x) {
in 1..10 -> print("x is in the range")
in validNumbers -> print("x is valid")
!in 10..20 -> print("x is outside the range")
else -> print("none of the above")
}
//sampleEnd
}
```
{kotlin-runnable="true" kotlin-min-compiler-version="1.3" id="kotlin-when-ranges"}
Check a value's type using the `is` or `!is` keywords. Due to [smart casts](typecasts.md#smart-casts), you can access the member functions
and properties of the type directly:
```kotlin
fun hasPrefix(input: Any): Boolean = when (input) {
is String -> input.startsWith("ID-")
else -> false
}
fun main() {
val testInput = "ID-98345"
println(hasPrefix(testInput))
// true
}
```
{kotlin-runnable="true" kotlin-min-compiler-version="1.3" id="kotlin-when-type-checks"}
Use `when` instead of a traditional `if`-`else` `if` chain.
Without a subject, the branch conditions are simply boolean expressions. The first branch with a `true` condition runs:
```kotlin
fun Int.isOdd() = this % 2 != 0
fun Int.isEven() = this % 2 == 0
fun main() {
//sampleStart
val x = 5
val y = 8
when {
x.isOdd() -> print("x is odd")
y.isEven() -> print("y is even")
else -> print("x+y is odd")
}
// x is odd
//sampleEnd
}
```
{kotlin-runnable="true" kotlin-min-compiler-version="1.3" id="kotlin-when-replace-if"}
Finally, capture the subject in a variable by using the following syntax:
```kotlin
fun main() {
val message = when (val input = "yes") {
"yes" -> "You said yes"
"no" -> "You said no"
else -> "Unrecognized input: $input"
}
println(message)
// You said yes
}
```
{kotlin-runnable="true" kotlin-min-compiler-version="1.3" id="kotlin-when-capture-subject"}
The scope of a variable introduced as the subject is restricted to the body of the `when` expression or statement.
### Guard conditions {id="guard-conditions-in-when-expressions"}
Guard conditions allow you to include more than one condition to the branches of a `when` expression or statement, making complex
control flow more explicit and concise. You can use guard conditions with `when` as long as it has a subject.
Place a guard condition after the primary condition in the same branch, separated by `if`:
```kotlin
sealed interface Animal {
data class Cat(val mouseHunter: Boolean) : Animal
data class Dog(val breed: String) : Animal
}
fun feedDog() = println("Feeding a dog")
fun feedCat() = println("Feeding a cat")
//sampleStart
fun feedAnimal(animal: Animal) {
when (animal) {
// Branch with only primary condition
// Calls feedDog() when animal is Dog
is Animal.Dog -> feedDog()
// Branch with both primary and guard conditions
// Calls feedCat() when animal is Cat and not mouseHunter
is Animal.Cat if !animal.mouseHunter -> feedCat()
// Prints "Unknown animal" if none of the above conditions match
else -> println("Unknown animal")
}
}
fun main() {
val animals = listOf(
Animal.Dog("Beagle"),
Animal.Cat(mouseHunter = false),
Animal.Cat(mouseHunter = true)
)
animals.forEach { feedAnimal(it) }
// Feeding a dog
// Feeding a cat
// Unknown animal
}
//sampleEnd
```
{kotlin-runnable="true" kotlin-min-compiler-version="2.2" id="kotlin-when-guard-conditions"}
You can't use guard conditions when you have multiple conditions separated by a comma. For example:
```kotlin
0, 1 -> print("x == 0 or x == 1")
```
In a single `when` expression or statement, you can combine branches with and without guard conditions.
The code in a branch with a guard condition runs only if both the primary condition and the guard condition evaluate to `true`.
If the primary condition doesn't match, the guard condition isn't evaluated.
Since `when` statements don't need to cover all cases, using guard conditions in `when` statements without an
`else` branch means that if no conditions match, no code is run.
Unlike statements, `when` expressions must cover all cases. If you use guard conditions in `when` expressions without an `else` branch,
the compiler requires you to handle every possible case to avoid runtime errors.
Combine multiple guard conditions within a single branch using the boolean operators `&&` (AND) or `||` (OR).
Use parentheses around the boolean expressions to [avoid confusion](coding-conventions.md#guard-conditions-in-when-expression):
```kotlin
when (animal) {
is Animal.Cat if (!animal.mouseHunter && animal.hungry) -> feedCat()
}
```
Guard conditions also support `else if`:
```kotlin
when (animal) {
// Checks if `animal` is `Dog`
is Animal.Dog -> feedDog()
// Guard condition that checks if `animal` is `Cat` and not `mouseHunter`
is Animal.Cat if !animal.mouseHunter -> feedCat()
// Calls giveLettuce() if none of the above conditions match and animal.eatsPlants is true
else if animal.eatsPlants -> giveLettuce()
// Prints "Unknown animal" if none of the above conditions match
else -> println("Unknown animal")
}
```
### Bytecode generation on the JVM
When you compile Kotlin code for JVM 21 or later, the compiler generates an [`invokedynamic`](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/invoke/package-summary.html)
instruction for eligible `when` expressions. This produces smaller bytecode, similar to the bytecode produced by Java `switch` statements.
The compiler uses `invokedynamic` with the [`SwitchBootstraps.typeSwitch()`](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/runtime/SwitchBootstraps.html)
method when all the following conditions are met:
* All conditions except for `else` are `is` or `null` checks.
* The `when` expression doesn't contain [guard conditions (`if`)](#guard-conditions-in-when-expressions).
* The conditions don't include types that can't be type-checked directly, such as mutable Kotlin collections
(`MutableList`) or function types (`kotlin.Function1`, `kotlin.Function2`, and so on).
* The `when` expression has at least two conditions besides `else`.
* All branches check the same subject of the `when` expression.
For example:
```kotlin
open class Shape
class Circle : Shape()
class Rectangle : Shape()
class Triangle : Shape()
fun countCorners(shape: Shape) = when (shape) {
is Circle -> 0
is Rectangle -> 4
is Triangle -> 3
else -> -1
}
```
The `when (shape)` expression here compiles to a single `invokedynamic` type switch instead of multiple `instanceof` checks
in the bytecode.
## For loops
Use the `for` loop to iterate through a [collection](collections-overview.md), [array](arrays.md), or [range](ranges.md):
```kotlin
for (item in collection) print(item)
```
The body of a `for` loop can be a block with curly braces `{}`.
```kotlin
fun main() {
val shoppingList = listOf("Milk", "Bananas", "Bread")
//sampleStart
println("Things to buy:")
for (item in shoppingList) {
println("- $item")
}
// Things to buy:
// - Milk
// - Bananas
// - Bread
//sampleEnd
}
```
{kotlin-runnable="true" kotlin-min-compiler-version="1.3" id="kotlin-for-loop"}
### Ranges
To iterate over a range of numbers, use a [range expression](ranges.md) with `..` and `..<` operators:
```kotlin
fun main() {
//sampleStart
println("Closed-ended range:")
for (i in 1..6) {
print(i)
}
// Closed-ended range:
// 123456
println("\nOpen-ended range:")
for (i in 1..<6) {
print(i)
}
// Open-ended range:
// 12345
println("\nReverse order in steps of 2:")
for (i in 6 downTo 0 step 2) {
print(i)
}
// Reverse order in steps of 2:
// 6420
//sampleEnd
}
```
{kotlin-runnable="true" kotlin-min-compiler-version="1.3" id="kotlin-for-loop-range"}
### Arrays
If you want to iterate through an array or a list with an index, you can use the `indices` property:
```kotlin
fun main() {
val routineSteps = arrayOf("Wake up", "Brush teeth", "Make coffee")
//sampleStart
for (i in routineSteps.indices) {
println(routineSteps[i])
}
// Wake up
// Brush teeth
// Make coffee
//sampleEnd
}
```
{kotlin-runnable="true" kotlin-min-compiler-version="1.3" id="kotlin-for-loop-array"}
Alternatively, you can use the [`.withIndex()`](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/with-index.html) function from the standard library:
```kotlin
fun main() {
val routineSteps = arrayOf("Wake up", "Brush teeth", "Make coffee")
//sampleStart
for ((index, value) in routineSteps.withIndex()) {
println("The step at $index is \"$value\"")
}
// The step at 0 is "Wake up"
// The step at 1 is "Brush teeth"
// The step at 2 is "Make coffee"
//sampleEnd
}
```
{kotlin-runnable="true" kotlin-min-compiler-version="1.3" id="kotlin-for-loop-array-index"}
### Iterators
The `for` loop iterates through anything that provides an [iterator](iterators.md). Collections provide iterators by
default, whereas ranges and arrays are compiled into index-based loops.
You can create your own iterators by providing a member or extension function called `iterator()` that returns an `Iterator<>`.
The `iterator()` function must have a `next()` function and a `hasNext()` function that returns a `Boolean`.
The easiest way to create your own iterator for a class is to inherit from the [`Iterable`](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/-iterable/) interface and override the
`iterator()`, `next()`, and `hasNext()` functions that are already there. For example:
```kotlin
class Booklet(val totalPages: Int) : Iterable {
override fun iterator(): Iterator {
return object : Iterator {
var current = 1
override fun hasNext() = current <= totalPages
override fun next() = current++
}
}
}
fun main() {
val booklet = Booklet(3)
for (page in booklet) {
println("Reading page $page")
}
// Reading page 1
// Reading page 2
// Reading page 3
}
```
{kotlin-runnable="true" kotlin-min-compiler-version="1.3" id="kotlin-for-loop-inherit-iterator"}
> Learn more about [interfaces](interfaces.md) and [inheritance](inheritance.md).
>
{style="tip"}
Alternatively, you can create the functions from scratch. In this case, add the `operator` keyword to the functions:
```kotlin
//sampleStart
class Booklet(val totalPages: Int) {
operator fun iterator(): Iterator {
return object {
var current = 1
operator fun hasNext() = current <= totalPages
operator fun next() = current++
}.let {
object : Iterator {
override fun hasNext() = it.hasNext()
override fun next() = it.next()
}
}
}
}
//sampleEnd
fun main() {
val booklet = Booklet(3)
for (page in booklet) {
println("Reading page $page")
}
// Reading page 1
// Reading page 2
// Reading page 3
}
```
{kotlin-runnable="true" kotlin-min-compiler-version="1.3" id="kotlin-for-loop-iterator-from-scratch"}
## While loops
`while` and `do-while` loops run the code in their body continuously while the condition is satisfied.
The difference between them is the condition checking time:
* `while` checks the condition and, if it's satisfied, runs the code in its body and then returns to the condition check.
* `do-while` runs the code in its body and then checks the condition. If it's satisfied, the loop repeats. So, the body of `do-while`
runs at least once, regardless of the condition.
For a `while` loop, place the condition to check in parentheses `()` and the body within curly braces `{}`:
```kotlin
fun main() {
var carsInGarage = 0
val maxCapacity = 3
//sampleStart
while (carsInGarage < maxCapacity) {
println("Car entered. Cars now in garage: ${++carsInGarage}")
}
// Car entered. Cars now in garage: 1
// Car entered. Cars now in garage: 2
// Car entered. Cars now in garage: 3
println("Garage is full!")
// Garage is full!
//sampleEnd
}
```
{kotlin-runnable="true" kotlin-min-compiler-version="1.3" id="kotlin-while-loop"}
For a `do-while` loop, place the body within curly braces `{}` first before the condition to check in parentheses `()`:
```kotlin
import kotlin.random.Random
fun main() {
var roll: Int
//sampleStart
do {
roll = Random.nextInt(1, 7)
println("Rolled a $roll")
} while (roll != 6)
// Rolled a 2
// Rolled a 6
println("Got a 6! Game over.")
// Got a 6! Game over.
//sampleEnd
}
```
{kotlin-runnable="true" kotlin-min-compiler-version="1.3" id="kotlin-do-while-loop"}
## Break and continue in loops
Kotlin supports traditional `break` and `continue` operators in loops. See [Returns and jumps](returns.md).