1. Introduction

Loops are one of the basic constructs of any programming language. They allow for repeated execution of one or more statements until a condition is met.

In this tutorial, we’re going to look at the different types of loops supported by Kotlin:

  • repeat
  • for loop
  • while loop
  • do..while loop

Let’s start by looking at the repeat statement.

2. Repeat

The repeat statement is the most basic of all the Kotlin loops. If we wish to simply repeat an operation n times, we can use repeat.

For example, let’s print Hello World two times:

repeat(2) {
    println("Hello World")
}

Additionally, we can also access the zero-based index of the current iteration:

repeat(2) { index ->
    println("Iteration ${index + 1}: Hello World")
}

3. For Loop

A for loop is used for iterating over a sequence of values. It executes a block of statements for each value in the sequence.

Let’s start by looking at the syntax of the for loop:

for (variableDeclaration 'in' expression) {
    // block of statements
}

Using Kotlin’s for loop, we can iterate over any Iterable such as a range, an array, or a collection.

3.1. Iterating Over a Range of Values

A range is a sequence of values comprising of a start, an end, and a step. In Kotlin, we can iterate over a range using a combination of the for loop and range expressions.

3.2. Iterating Over an Array

To begin with, let’s declare an array of vowels:

val vowels = arrayOf('a', 'e', 'i', 'o', 'u')

We can now iterate over the elements of this array using the for loop:

for (vowel in vowels) {
    println(vowel)
}

Next, let’s iterate over the array indices. We can do this by looping over the indices property:

for (index in vowels.indices) {
    println(vowels[index])
}

The indices property returns only the array indices as an IntRange that we can iterate over. We have to fetch the array elements separately using the returned indices.

Let’s look at an alternate way that gives us both the indices and elements at the same time:

for ((index, vowel) in vowels.withIndex()) {
    println("The vowel at index $index is: $vowel")
}

Let’s understand the interesting syntax of this for a loop a bit more:

for ((index, vowel) in vowels.withIndex()) { ... }

The withIndex() method returns an IndexedValue instance. We use the destructuring declarations and capture the (index, value) properties returned by the component1() and component2() methods of the IndexedValue into the index and vowel variables respectively*.*

3.3. Iterating Over a List

A list is a generic ordered collection of elements that can contain duplicate values. We can use the for loop to iterate over the elements of a list. We can also iterate over a list by the indices of its elements.

3.4. Iterating Over a Map

Let’s start by declaring a Map of capital city names keyed by country names:

val capitalCityByCountry = mapOf("Netherlands" to "Amsterdam",
  "Germany" to "Berlin", "USA" to "Washington, D.C.")

We can now iterate over the map entries and access both the key and the value of each entry:

for (entry in capitalCityByCountry) {
    println("The capital city of ${entry.key} is ${entry.value}")
}

We can iterate over the map’s keys using the keys property:

for (country in capitalCityByCountry.keys) {
    println(country)
}

Here, we iterate over the keys property that returns a read-only Set of the map’s keys.

Similarly, we can iterate over the map’s values using the values property:

for (capitalCity in capitalCityByCountry.values) {
    println(capitalCity)
}

Finally, as in the case of arrays and lists, we can use the destructuring declarations when iterating over a map as well:

for ((country, capitalCity) in capitalCityByCountry) {
    println("The capital city of $country is $capitalCity")
}

The destructuring declaration gives us access to the key and value of each entry as we iterate over the map.

3.5. Functional Style Iteration Using forEach

So far, we looked at the traditional style of iterating over arrays, collections, and ranges using the for loop.

To code in a functional style, we can use forEach instead.

4. While Loop

The while loop repeats a block of statements while its controlling Boolean-expression is true.

Let’s look at the syntax first:

while (boolean-expression) {
    // statements here
}

Next, let’s look at an example:

var counter = 0
while (counter < 5) {
    println("while loop counter: " + counter++)
}

This prints the counter values from 0 to 4.

In a while loop, the boolean-expression is evaluated first. This means that if the boolean-expression evaluates to false for the very first iteration, the block of statements will never be executed.

Here is a while loop whose block of statements will never be executed:

while (false) {
    println("This will never be printed")
}

Here is an infinite while loop:

while (true) {
    println("I am in an infinite loop")
}

5. Do..While Loop

The do..while loop is a variant of the while loop in that the boolean-expression is evaluated after each iteration:

do {
    // statements here
} while (boolean-expression)

Let’s look at a simple example:

var counter = 0
do {
    println("do..while counter: " + counter++)
} while (counter < 5)

This prints the counter values from 0 to 4.

Because the boolean-expression is evaluated at the end of each loop, the do..while loop is executed at least once.

Here is a do..while loop whose block of statements will be executed exactly once:

do {
    println("This will be printed exactly once")
} while (false)

6. The return, break, and continue Keywords

Sometimes, we might wish to terminate a loop or skip the next iteration of a loop. We can use the structural jump expressions in such cases.

Kotlin has three structural jump expressions: return, break, and continue. 

However, when a loop contains more than one break or continue statements, it is considered a code-smell and must be avoided.

7. Loop with Multiple Variables

So far, we’ve learned various ways to loop with a single variable. In this section, we’ll expand our knowledge of loops to multiple variables.

7.1. The zip Operator

Let’s imagine that we’ve to organize multiple two-player matches between two teams:

val teamA = listOf("A1", "A2", "A3")
val teamB = listOf("B1", "B2")

As the number of players in the two teams is different, not all players can play simultaneously. However, we can pair them up in the order of their appearance in the list using the zip operator and ignore the third player, A3, from teamA:

teamA zip teamB

Let’s create a showMatches() function that will generate and show matches between any two teams:

fun showMatches(team1: List<String>, team2: List<String>) {
    for ((player1, player2) in team1 zip team2)
        println("$player1 vs $player2")
}

Next, let’s verify the matches that’ll be generated when we call showMatches(teamA, teamB):

A1 vs B1
A2 vs B2

Alternatively, we could also transform this problem of looping through multiple variables, namely player1 and player2, to looping through a single variable match:

fun showMatchLabels(team1: List<String>, team2: List<String>) {
    matches = team1.zip(team2) { player1, player2 -> "$player1 vs $player2" }
    for (match in matches)
        println(match)
}

Essentially, we combined the two lists into a single list that now contains labels for the matches.

7.2. Multiplication Table

Let’s advance our understanding of looping with multiple variables by applying concepts of ranges and the zip operator to generate multiplication tables, where each row shows up in the format:

factor x multiplier = result

As the factor will remain the same in all the rows, we’ll have to loop through two multiplier and result variables*.* Further, we’ll need two ranges in our loop. While the first range will hold the list of multipliers corresponding to different rows, on the other hand, the second range will hold the result values.

First, let’s go ahead and write the printMultiplicationTable() function:

fun printMultiplicationTable(factor: Int, start: Int, end: Int) {
    val multipliers = start..end
    val multiplicationResults = factor * start..factor * end step factor
    for ((multiplier, result) in multipliers zip multiplicationResults)
        println("$factor x $multiplier = $result")
}

Next, we should definitely note that multiplicationResults is actually a progression with a step value equal to the factor.

Finally, let’s verify this function to show the multiplication table of 27 for rows starting at 3 and ending at 7:

printMultiplicationTable(27, 3, 7)

We can see that the output shown in the console is as expected:

27 x 3 = 81
27 x 4 = 108
27 x 5 = 135
27 x 6 = 162
27 x 7 = 189

8. Conclusion

In this tutorial, we looked at various loops supported by Kotlin. To begin with, we looked at repeat, which is the simplest of the loop statements. Then, we looked at the for loop and how it can be used to iterate over ranges, arrays, and collections. Next, we looked at the while and do..while loops and the subtle differences between them.

Further, we extended our understanding to looping with multiple variables. Finally, we looked at Kotlin’s structural jump expressions: return, break, and continue.

As always, the source code is available over on GitHub.