Kotlin - Loops (for/while)
Kotlin Loops (for/while)
Loops allow you to execute code repeatedly. Learn Kotlin's for loops, while loops, iteration patterns, and loop control statements like break and continue.
for Loops
Key Concept: Kotlin's for loop is different from Java/C-style for loops. It's designed for iterating over collections and ranges using the iterator pattern.
Basic for Loop with Ranges
// Iterate over a range
for (i in 1..5) {
println("Number: $i")
}
// Output: 1, 2, 3, 4, 5
// Until (exclusive end)
for (i in 1 until 5) {
println("Number: $i")
}
// Output: 1, 2, 3, 4
// Downward iteration
for (i in 5 downTo 1) {
println("Number: $i")
}
// Output: 5, 4, 3, 2, 1
// With step
for (i in 1..10 step 2) {
println("Odd number: $i")
}
// Output: 1, 3, 5, 7, 9
Iterating Over Collections
// Iterate over lists
val fruits = listOf("apple", "banana", "cherry", "date")
for (fruit in fruits) {
println("Fruit: $fruit")
}
// Iterate over arrays
val numbers = arrayOf(10, 20, 30, 40, 50)
for (number in numbers) {
println("Number: $number")
}
// Iterate over strings (character by character)
val text = "Kotlin"
for (char in text) {
println("Character: $char")
}
// Iterate over maps
val scores = mapOf("Alice" to 95, "Bob" to 87, "Charlie" to 92)
for ((name, score) in scores) {
println("$name scored $score")
}
// Or with entry
for (entry in scores) {
println("${entry.key} scored ${entry.value}")
}
for Loop with Indices
val languages = listOf("Kotlin", "Java", "Python", "JavaScript")
// Using indices
for (i in languages.indices) {
println("Language $i: ${languages[i]}")
}
// Using withIndex()
for ((index, language) in languages.withIndex()) {
println("Language $index: $language")
}
// Using forEachIndexed (alternative)
languages.forEachIndexed { index, language ->
println("Language $index: $language")
}
// Custom index range
for (i in 1..languages.size) {
println("Position $i: ${languages[i - 1]}")
}
while Loops
Basic while Loop
// Basic while loop
var counter = 1
while (counter <= 5) {
println("Counter: $counter")
counter++
}
// While with condition checking
var input: String? = null
while (input != "quit") {
println("Enter 'quit' to exit or anything else to continue:")
input = readlnOrNull() // In real app, get user input
if (input != "quit") {
println("You entered: $input")
}
}
// Processing collections with while
val numbers = mutableListOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
while (numbers.isNotEmpty()) {
val number = numbers.removeAt(0)
if (number % 2 == 0) {
println("Even number removed: $number")
}
}
do-while Loop
// do-while executes at least once
var attempts = 0
var success = false
do {
attempts++
println("Attempt $attempts")
// Simulate some operation
success = (1..10).random() > 7 // 30% chance of success
if (!success) {
println("Failed, trying again...")
}
} while (!success && attempts < 5)
if (success) {
println("Success after $attempts attempts!")
} else {
println("Failed after $attempts attempts")
}
// Menu system example
var choice: Int
do {
println("""
Menu:
1. Option A
2. Option B
3. Exit
Enter choice:
""".trimIndent())
choice = (1..3).random() // Simulate user input
println("Selected: $choice")
when (choice) {
1 -> println("Executing Option A")
2 -> println("Executing Option B")
3 -> println("Exiting...")
else -> println("Invalid choice, try again")
}
} while (choice != 3)
Loop Control Statements
break Statement
// Break out of loop early
for (i in 1..10) {
if (i == 6) {
println("Breaking at $i")
break
}
println("Processing: $i")
}
// Output: 1, 2, 3, 4, 5, then "Breaking at 6"
// Break in while loop
var count = 0
while (true) { // Infinite loop
count++
println("Count: $count")
if (count >= 3) {
println("Breaking infinite loop")
break
}
}
// Finding first match
val numbers = listOf(2, 4, 7, 8, 10, 13, 16)
var firstOdd: Int? = null
for (number in numbers) {
if (number % 2 == 1) {
firstOdd = number
println("Found first odd number: $firstOdd")
break
}
}
if (firstOdd == null) {
println("No odd numbers found")
}
continue Statement
// Skip current iteration
for (i in 1..10) {
if (i % 2 == 0) {
continue // Skip even numbers
}
println("Odd number: $i")
}
// Output: 1, 3, 5, 7, 9
// Process only valid data
val data = listOf("", "hello", null, "world", "", "kotlin")
for (item in data) {
if (item.isNullOrBlank()) {
continue // Skip empty/null items
}
println("Processing: ${item.uppercase()}")
}
// Skip based on condition
val scores = listOf(85, 92, 67, 78, 95, 88, 72)
for (score in scores) {
if (score < 70) {
println("Skipping failing score: $score")
continue
}
println("Passing score: $score")
}
Labeled break and continue
// Nested loops with labels
outer@ for (i in 1..3) {
inner@ for (j in 1..3) {
if (i == 2 && j == 2) {
println("Breaking outer loop at i=$i, j=$j")
break@outer // Break the outer loop
}
println("i=$i, j=$j")
}
}
// Continue with labels
outer@ for (i in 1..3) {
println("Outer loop i=$i")
for (j in 1..3) {
if (j == 2) {
println("Continuing outer loop")
continue@outer // Continue the outer loop
}
println(" Inner loop j=$j")
}
}
// Practical example: matrix processing
val matrix = arrayOf(
arrayOf(1, 2, 3),
arrayOf(4, 0, 6), // Contains zero
arrayOf(7, 8, 9)
)
matrixLoop@ for ((rowIndex, row) in matrix.withIndex()) {
for ((colIndex, value) in row.withIndex()) {
if (value == 0) {
println("Found zero at position [$rowIndex][$colIndex]")
break@matrixLoop // Stop processing entire matrix
}
println("Processing value $value at [$rowIndex][$colIndex]")
}
}
Advanced Loop Patterns
Iterating with Conditions
// Loop until condition met
fun findTarget(numbers: List, target: Int): Int? {
for ((index, number) in numbers.withIndex()) {
if (number == target) {
return index
}
}
return null
}
// Multiple exit conditions
fun processData(data: List): List {
val results = mutableListOf()
for (item in data) {
// Multiple conditions for skipping
when {
item.isBlank() -> continue
item.startsWith("#") -> continue // Skip comments
item.length > 50 -> {
println("Item too long, stopping: ${item.take(20)}...")
break
}
else -> results.add(item.uppercase())
}
}
return results
}
val testData = listOf("hello", "", "#comment", "world", "kotlin", "programming")
println(processData(testData))
Functional Style Alternatives
val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
// Traditional loop
val evenNumbers = mutableListOf()
for (number in numbers) {
if (number % 2 == 0) {
evenNumbers.add(number * 2)
}
}
println("Traditional: $evenNumbers")
// Functional style (preferred in Kotlin)
val functionalEven = numbers
.filter { it % 2 == 0 }
.map { it * 2 }
println("Functional: $functionalEven")
// forEach (when you need side effects)
numbers.forEach { number ->
if (number % 2 == 0) {
println("Even: $number")
}
}
// Using sequences for lazy evaluation
val lazyResult = numbers.asSequence()
.filter { it % 2 == 0 }
.map { it * 2 }
.take(3)
.toList()
println("Lazy: $lazyResult")
Real-World Examples
Data Processing Loop
data class Student(val name: String, val grades: List)
fun processStudents(students: List) {
for ((index, student) in students.withIndex()) {
println("Processing student ${index + 1}: ${student.name}")
if (student.grades.isEmpty()) {
println(" No grades available, skipping...")
continue
}
var sum = 0
var validGrades = 0
for (grade in student.grades) {
if (grade < 0 || grade > 100) {
println(" Invalid grade: $grade, skipping...")
continue
}
sum += grade
validGrades++
}
if (validGrades == 0) {
println(" No valid grades found")
continue
}
val average = sum.toDouble() / validGrades
println(" Average: %.2f".format(average))
if (average >= 90) {
println(" Grade: A (Excellent!)")
} else if (average >= 80) {
println(" Grade: B (Good)")
} else if (average >= 70) {
println(" Grade: C (Satisfactory)")
} else {
println(" Grade: F (Needs improvement)")
}
println()
}
}
val students = listOf(
Student("Alice", listOf(95, 87, 92, 89)),
Student("Bob", listOf(78, 82, 85)),
Student("Charlie", listOf()), // No grades
Student("Diana", listOf(67, 72, 69, 75))
)
processStudents(students)
Game Loop Example
class GameEngine {
private var running = true
private var score = 0
private var level = 1
fun gameLoop() {
println("Game started!")
gameRunning@ while (running) {
println("\n--- Level $level ---")
// Simulate level
for (round in 1..5) {
println("Round $round")
// Simulate game action
val success = (1..10).random() > 3 // 70% success rate
if (success) {
score += 10
println("Success! Score: $score")
} else {
println("Failed this round")
if (score > 0) score -= 5
// Check game over condition
if (score < 0) {
println("Game Over! Final score: $score")
break@gameRunning
}
}
// Random events
val event = (1..20).random()
when (event) {
1 -> {
println("Bonus round! Double points!")
score += 20
}
2 -> {
println("Challenge failed! Lose points!")
score -= 15
}
}
}
// Level completion
if (score >= level * 50) {
level++
println("Level up! Now on level $level")
} else {
println("Level failed. Try again!")
continue@gameRunning
}
// Check win condition
if (level > 5) {
println("Congratulations! You won the game!")
running = false
}
}
println("Final Stats - Level: $level, Score: $score")
}
}
// Run the game
val game = GameEngine()
game.gameLoop()
File Processing with Error Handling
fun processLogFile(lines: List): Map {
val errorCounts = mutableMapOf()
var lineNumber = 0
lineLoop@ for (line in lines) {
lineNumber++
// Skip empty lines and comments
if (line.isBlank() || line.startsWith("#")) {
continue
}
// Process log entry
val parts = line.split(" ", limit = 3)
if (parts.size < 3) {
println("Warning: Invalid log format at line $lineNumber: $line")
continue
}
val (timestamp, level, message) = parts
// Only process error and warning levels
when (level.uppercase()) {
"ERROR", "WARN", "WARNING" -> {
// Extract error type from message
val errorType = message.split(":").firstOrNull()?.trim() ?: "Unknown"
errorCounts[errorType] = errorCounts.getOrDefault(errorType, 0) + 1
}
"DEBUG", "TRACE" -> continue // Skip debug messages
"INFO" -> {
// Just count info messages
errorCounts["INFO"] = errorCounts.getOrDefault("INFO", 0) + 1
}
else -> {
println("Unknown log level '$level' at line $lineNumber")
continue
}
}
// Stop if we find too many errors
val totalErrors = errorCounts.filterKeys { it != "INFO" }.values.sum()
if (totalErrors > 100) {
println("Too many errors found, stopping processing")
break@lineLoop
}
}
return errorCounts
}
// Simulate log file
val logLines = listOf(
"2023-01-01 INFO Application started",
"2023-01-01 ERROR DatabaseConnection: Failed to connect",
"2023-01-01 WARN MemoryUsage: High memory usage detected",
"",
"# This is a comment",
"2023-01-01 ERROR NetworkTimeout: Request timed out",
"2023-01-01 DEBUG Processing user request",
"2023-01-01 ERROR DatabaseConnection: Failed to connect",
"Invalid log line",
"2023-01-01 INFO User logged in"
)
val results = processLogFile(logLines)
println("Error summary:")
results.forEach { (type, count) ->
println("$type: $count occurrences")
}
Best Practices
✅ Good Practices
- Use for loops for iterating over collections and ranges
- Prefer functional alternatives (map, filter, forEach) when appropriate
- Use meaningful variable names in loops
- Keep loop bodies simple and focused
- Use labeled breaks/continues for complex nested loops
- Prefer while loops when the number of iterations is unknown
❌ Avoid
- Complex logic inside loop conditions
- Modifying collection while iterating (use iterator or functional methods)
- Deeply nested loops without clear purpose
- Infinite loops without proper exit conditions
- Using loops when functional alternatives are clearer
Architecture Note: Kotlin encourages functional programming patterns. While loops are essential, consider using collection operations (map, filter, reduce) for data transformations as they're often more readable and less error-prone.
Practice Exercises
- Create a program that finds all prime numbers up to 100 using loops
- Implement a simple calculator that processes a list of operations
- Build a text analyzer that counts words, sentences, and paragraphs
- Create a multiplication table generator using nested loops
- Implement a simple game where players guess a number
Quick Quiz
- What's the difference between `1..5` and `1 until 5`?
- How do you iterate over both index and value of a list?
- What's the difference between `break` and `continue`?
- When should you use a while loop vs a for loop?
Show answers
- `1..5` includes 5 (closed range), `1 until 5` excludes 5 (half-open range)
- Use `list.withIndex()` or iterate over `list.indices`
- `break` exits the entire loop, `continue` skips to the next iteration
- Use for loops for known collections/ranges, while loops when the number of iterations is unknown