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:
Each branch in an if
expression can be a block, where the value of the last expression becomes the result:
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:
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 |
---|---|
// 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"
}
|
// 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 | Without subject |
---|---|
when(x) { ... }
|
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:
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, sealed
class, or one of their nullable counterparts, you can cover all cases without an else
branch:
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:
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:
Use expressions that evaluate to true
or false
as branch conditions:
Check whether a value is or isn't contained in a range or collection using the in
or !in
keywords:
Check a value's type using the is
or !is
keywords. Due to smart casts, you can access the member functions and properties of the type directly:
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:
Finally, capture the subject in a variable by using the following syntax:
The scope of a variable introduced as the subject is restricted to the body of the when
expression or statement.
Guard conditions
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
:
You can't use guard conditions when you have multiple conditions separated by a comma. For example:
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:
Guard conditions also support else if
:
For loops
Use the for
loop to iterate through a collection, array, or range:
The body of a for
loop can be a block with curly braces {}
.
Ranges
To iterate over a range of numbers, use a range expression with ..
and ..<
operators:
Arrays
If you want to iterate through an array or a list with an index, you can use the indices
property:
Alternatively, you can use the .withIndex()
function from the standard library:
Iterators
The for
loop iterates through anything that provides an iterator. 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<T>
interface and override the iterator()
, next()
, and hasNext()
functions that are already there. For example:
Alternatively, you can create the functions from scratch. In this case, add the operator
keyword to the functions:
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 ofdo-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 {}
:
For a do-while
loop, place the body within curly braces {}
first before the condition to check in parentheses ()
:
Break and continue in loops
Kotlin supports traditional break
and continue
operators in loops. See Returns and jumps.