Hello! Welcome to the fourth lesson in our "Learn Kotlin Syntax" course.
In our last lesson, we explored how Kotlin's string templates and multiline strings make text manipulation clean and intuitive. You learned to embed variables and expressions directly into strings, a significant improvement over traditional concatenation.
Today, we'll move from handling data to controlling program flow. The objective of this lesson is to learn how to write a 'for' loop to iterate over ranges, progressions, and collections. As a Java developer, you're familiar with for loops, but you'll find Kotlin's for-in loop to be a more powerful and versatile construct that applies uniformly to many different kinds of sequences.
1. The for Loop: Iterating Over Collections
In Kotlin, the for loop is exclusively a "for-each" style loop, similar to Java's enhanced for loop. It iterates over anything that provides an iterator—this includes collections, arrays, ranges, and even strings.
The basic syntax is straightforward: for (item in collection) { ... }.
Let's start by looking at the most common use case: iterating over a list.
The official Kotlin documentation provides a clear, simple example of the basic for loop syntax used with a list.
In this resource from kotlinlang.org, read the short section titled 'For loops'. It shows the fundamental syntax that we'll build upon.
As you saw, the syntax is clean and readable:
val items = listOf("apple", "banana", "kiwi")
for (item in items) {
println(item)
}
This is the idiomatic way to loop in Kotlin. While you can use the Iterator interface manually with a while loop (as you might in older Java code), it's verbose and generally unnecessary. The for loop handles the iterator logic for you under the hood.
This next video provides an excellent comparison between the manual iterator approach and the idiomatic Kotlin for loop.
Iterator (and forEach) Explained - Kotlin Collections
This video from Cody Engel clearly demonstrates why the Kotlin for loop is preferred over manual iteration.
Watch from 00:58 to 05:35. The first part (until 03:44) shows the verbose while (iterator.hasNext()) pattern, which will be familiar from Java. The second part introduces the concise for (item in collection) loop, highlighting its safety and readability.
2. Iterating Over Ranges and Progressions
A powerful feature of Kotlin's for loop is its ability to iterate over numerical sequences. This is where it goes beyond Java's enhanced for loop and often replaces the classic C-style for (int i = 0; i < n; i++). These sequences are created using ranges and progressions.
This video provides a comprehensive tour of the different ways to create and control these sequences.
Kotlin for Beginners - Part 10 - FOR-LOOP & RANGES
This video from Coding in Flow is a perfect guide to ranges and progressions. It covers everything from simple ranges to custom steps.
Watch from 04:19 to 08:11. This covers the essential syntax for creating sequences: Inclusive ranges with the .. operator (e.g., 1..10). Exclusive ranges with until and counting down with downTo. Custom steps using the step keyword.
Let's summarize the key tools for creating these sequences:
..(Range Operator): Creates an inclusive range.1..4includes 1, 2, 3, and 4.for (i in 1..4) { print("$i ") // Prints: 1 2 3 4 }..<oruntil: Creates an exclusive range (the end value is not included).1..<4and1 until 4are equivalent and include 1, 2, and 3. The..<operator was introduced in Kotlin 1.8 and is becoming more common.for (i in 1 until 4) { print("$i ") // Prints: 1 2 3 }downTo: Iterates in reverse order.for (i in 4 downTo 1) { print("$i ") // Prints: 4 3 2 1 }step: Specifies the increment for the iteration. It can be combined with any of the above.for (i in 1..10 step 2) { print("$i ") // Prints: 1 3 5 7 9 } for (i in 10 downTo 0 step 3) { print("$i ") // Prints: 10 7 4 1 }
These constructs—ranges modified by downTo and step—are technically called progressions. A progression is defined by a start value, an end value, and a step. You can find more details in the official documentation on Ranges and progressions, but the key takeaway is that for loops can iterate over them seamlessly.
3. Iterating with an Index
A common requirement is to access the index of the element during iteration. In Java, this is the primary use case for the classic for loop. Kotlin provides two idiomatic ways to achieve this without resorting to a manual counter variable.
Let's turn back to the official documentation to see how.
This part of the documentation shows the two standard Kotlin patterns for accessing the index within a loop.
Read the subsection titled 'Arrays' (the concepts apply to lists as well). Focus on the two examples: one using the indices property and the other using the .withIndex() function.
Let's break down these two approaches:
-
Using the
indicesproperty:
Every array and list has anindicesproperty, which is simply a range of its valid indices (e.g.,0..2for a 3-element list). You can iterate over this range to get the index. This is useful when you primarily need the index to access elements.val items = listOf("A", "B", "C") for (i in items.indices) { println("Item at index $i is ${items[i]}") }Output:
Item at index 0 is A Item at index 1 is B Item at index 2 is C -
Using the
withIndex()function:
This is often the more elegant solution. ThewithIndex()function returns a sequence of pairs, each containing an index and the value at that index. You can then use a destructuring declaration to unpack this pair directly into two variables.val items = listOf("A", "B", "C") for ((index, value) in items.withIndex()) { println("Item at index $index is $value") }The output is identical, but the code is arguably more readable as you don't need to perform the
items[i]lookup yourself.
4. Hands-On Practice
Time to put it all together. In your IDE, create a main function and solve the following small problem.
Goal: Simulate processing a list of tasks from a queue.
- Create a
valnamedtaskIdsand initialize it with alistOfsome strings, for example:listOf("a-101", "b-205", "c-333", "d-404", "e-512"). - First, log all tasks:
- Write a
forloop that iterates throughtaskIdsusingwithIndex(). - Inside the loop, print a message for each task, including its 1-based position and its ID. For example:
Processing task 1/5: a-101.
- Write a
- Next, simulate a cleanup process:
- Add a blank
println()for spacing. - Print a message like "--- Running cleanup on even-numbered tasks ---".
- Write a
forloop that iterates over thetaskIds.indicesrange with astepof 2. - Inside this loop, print a message for each task being cleaned up. For example:
Cleaning up task a-101.
- Add a blank
Click to see a possible solution
fun main() {
val taskIds = listOf("a-101", "b-205", "c-333", "d-404", "e-512")
// 1. Log all tasks
println("--- Processing all tasks ---")
for ((index, id) in taskIds.withIndex()) {
println("Processing task ${index + 1}/${taskIds.size}: $id")
}
println() // For spacing
// 2. Run cleanup on even-numbered tasks (indices 0, 2, 4...)
println("--- Running cleanup on even-numbered tasks ---")
for (i in taskIds.indices step 2) {
println("Cleaning up task ${taskIds[i]}")
}
}
Conclusion
In this lesson, you've learned how to use Kotlin's versatile for loop to handle a wide variety of iteration tasks in a concise and readable way.
Key Takeaways:
- Kotlin's
forloop is afor-in(or for-each) loop that works on anyIterableobject. - You can iterate over collections like
Listto process each element. - You can iterate over ranges of numbers using
..(inclusive) and..<oruntil(exclusive). - You can create advanced progressions by combining ranges with
downTo(for reverse order) andstep(for custom increments). - To access the index during iteration, use either the
collection.indicesproperty or the more idiomaticcollection.withIndex()function with a destructuring declaration.
Next Lesson Preview:
Now that you can control repetition with loops, we'll look at controlling decisions. In the next lesson, we will explore how Kotlin enhances the if statement, turning it into an expression that can return a value. This is another feature that helps write more concise and functional-style code.