Kotlin Control Flow: if, when, for Loops, while, Ranges & Break/Continue
1. Conditional Statements: if, if-else, when
What are conditional statements in Kotlin?
Conditional statements in Kotlin allow you to execute different code blocks based on specific conditions. Kotlin provides flexible tools for control flow, including if, if-else, and when, which can be used as statements or expressions.
if: Executes a block if a condition is true.
if-else: Executes one block if true, another if false.
when: A multi-branch expression similar to switch, supporting multiple conditions, ranges, and guard clauses for more explicit logic.
Syntax:
if (condition) {
// true block
} else {
// false block
}
when (variable) {
value1 -> // block
value2 -> // block
else -> // default
}
Use Case: Decision-making based on values (e.g., grading, validation).
Example:
// if and if-else example
fun grade(score: Int): String {
if (score >= 90) {
return "A"
} else if (score >= 80) {
return "B"
} else {
return "C"
}
}
// when example
fun describeAge(age: Int): String {
return when {
age < 18 -> "Minor"
age in 18..64 -> "Adult"
else -> "Senior"
}
}
// Main function
fun main() {
val score = 85
println("Grade for $score: ${grade(score)}")
val age = 25
println("Description for age $age: ${describeAge(age)}")
}
Grade for 85: B
Description for age 25: Adult
Note: if-else chains conditions; when uses in for ranges and else for default. when can replace if-else for cleaner code.
2. Loops: for, while, do-while
What are loops in Kotlin?
Loops in Kotlin enable repetitive execution of code blocks. Kotlin supports for for iterating over ranges, collections, or arrays; while for condition-based repetition; and do-while for executing at least once before checking the condition.
for Loop: Iterates over ranges, collections, or arrays. Syntax: for (item in collection) { // code }.
while Loop: Repeats while a condition is true. Syntax: while (condition) { // code }.
do-while Loop: Executes at least once, then repeats while condition is true. Syntax: do { // code } while (condition).
Use Case: Iterating over data, processing lists, or repeating tasks.
Example:
// for loop example
fun forLoop() {
val numbers = listOf(1, 2, 3, 4, 5)
for (num in numbers) {
println("Number: $num")
}
// Range-based for loop
for (i in 1..5) {
println("Range: $i")
}
}
// while loop example
fun whileLoop() {
var count = 0
while (count < 3) {
println("While count: $count")
count++
}
}
// do-while loop example
fun doWhileLoop() {
var count = 0
do {
println("Do-while count: $count")
count++
} while (count < 3)
}
// Main function
fun main() {
forLoop()
whileLoop()
doWhileLoop()
}
Number: 1
Number: 2
Number: 3
Number: 4
Number: 5
Range: 1
Range: 2
Range: 3
Range: 4
Range: 5
While count: 0
While count: 1
While count: 2
Do-while count: 0
Do-while count: 1
Do-while count: 2
Note: for uses in for iteration; 1..5 is a range. while checks condition before execution; do-while executes at least once.
3. Ranges and Progressions
What are ranges and progressions in Kotlin?
Ranges represent a sequence of values from start to end (inclusive by default). Syntax: start..end (inclusive), start until end (exclusive). Progressions customize step size (e.g., 1..10 step 2). They are immutable, iterable, and support contains, first, last, etc.
Use Case: Iterating with for loops, validating values (e.g., age in 18..65).
Example:
// Ranges and progressions
fun rangesExample() {
// Basic range
val ages = 18..65
println("Ages range: $ages")
println("Contains 30: ${30 in ages}")
// Exclusive range
val exclusive = 1 until 5
println("Exclusive range: $exclusive")
// Progression with step
val evens = 2..10 step 2
println("Even numbers: $evens")
// Descending progression
val descending = 10 downTo 1 step 2
println("Descending evens: $descending")
// Iterate over range
for (i in 1..5) {
println("Iteration: $i")
}
}
fun main() {
rangesExample()
}
Ages range: 18..65
Contains 30: true
Exclusive range: 1 until 5
Even numbers: 2..10 step 2
Descending evens: 10 downTo 1 step 2
Iteration: 1
Iteration: 2
Iteration: 3
Iteration: 4
Iteration: 5
Note: in checks membership in ranges. step customizes progression; downTo for descending.
4. Breaking and Continuing Loops
How do you break and continue loops in Kotlin?
break: Exits the nearest enclosing loop. continue: Skips the current iteration and moves to the next. Use Case: Early loop termination or skipping invalid data. Syntax: break or continue inside loop body. Labeled breaks for nested loops (e.g., outer@ for ... { break@outer }).
Example:
// break and continue example
fun loopControl() {
// for loop with break
for (i in 1..10) {
if (i == 5) {
break // Exit loop
}
println("For i: $i")
}
// for loop with continue
for (i in 1..5) {
if (i % 2 == 0) {
continue // Skip even numbers
}
println("Odd i: $i")
}
// while with break
var count = 0
while (count < 5) {
if (count == 3) {
break
}
println("While count: $count")
count++
}
// Labeled break for nested loops
outer@ for (i in 1..3) {
for (j in 1..3) {
if (i == 2 && j == 2) {
break@outer // Exit outer loop
}
println("Nested: ($i, $j)")
}
}
}
fun main() {
loopControl()
}
For i: 1
For i: 2
For i: 3
For i: 4
Odd i: 1
Odd i: 3
Odd i: 5
While count: 0
While count: 1
While count: 2
Nested: (1, 1)
Nested: (1, 2)
Nested: (1, 3)
Nested: (2, 1)
Note: break exits the loop; continue skips iterations. Labeled break@outer exits nested loops.
5. Comprehensive Example Combining All Control Flow Concepts
Example:
// Comprehensive control flow example
import kotlin.random.Random
fun processGrades(scores: List) {
// if-else
val average = scores.average()
val status = if (average >= 70) {
"Passed"
} else {
"Failed"
}
println("Average: $average, Status: $status")
// when expression
val grade = when {
average >= 90 -> "A"
average in 80.0..89.99 -> "B"
average in 70.0..79.99 -> "C"
else -> "F"
}
println("Grade: $grade")
// for loop with range
println("Scores:")
for (score in scores.indices) {
val currentScore = scores[score]
if (currentScore < 60) {
continue // Skip failing scores
}
println("Score $score: $currentScore")
if (score == scores.size - 1) {
break // Exit after last score
}
}
// while loop
var index = 0
while (index < scores.size) {
val score = scores[index]
if (score > 80) {
println("High score at index $index: $score")
}
index++
}
// do-while loop
index = 0
do {
println("Do-while index: $index")
index++
} while (index < 2)
// Range with progression
val evens = 2..10 step 2
println("Even numbers: $evens")
}
fun main() {
val scores = listOf(85, 92, 78, 55, 88)
processGrades(scores)
}
Average: 79.6, Status: Passed
Grade: C
Scores:
Score 0: 85
Score 1: 92
Score 4: 88
High score at index 0: 85
High score at index 1: 92
High score at index 4: 88
Do-while index: 0
Do-while index: 1
Even numbers: 2..10 step 2
Description: if-else: Determines pass/fail based on average. when: Assigns letter grade. for with continue/break: Processes scores, skipping failures. while: Finds high scores. do-while: Runs at least once. Range: Generates even numbers with step. Includes input validation implicitly via average().
6. Common Mistakes and Best Practices
Common Mistakes:
- Conditional: Forgetting
elseinif, leading to incomplete logic. Misusingwhenwithoutelsefor exhaustive conditions. - Loops: Infinite
whileloops without update orbreak. Modifying collections duringforiteration, causing ConcurrentModificationException. - Ranges: Using
..for exclusive ranges (useuntilinstead). Incorrectstepvalues, causing unexpected sequences. - Breaking/Continuing: Using
continueorbreakoutside loops, causing SyntaxError. Overusing labeled breaks, reducing readability. - General: Not handling exceptions in loops. Inconsistent indentation in code blocks.
Best Practices:
- Conditional: Use
whenfor multiple conditions;if-elsefor simple binary choices. Includeelseinwhenfor exhaustive matching. - Loops: Prefer
forwithinfor ranges/collections;whilefor condition-based repetition. Usedo-whilewhen the body must execute at least once. - Ranges: Use
untilfor exclusive ranges;stepfor custom progressions. Validate range bounds to avoid empty iterations. - Breaking/Continuing: Use
breakfor early exits;continuefor skipping iterations. Label loops for nestedbreak/continuewhen needed. - General: Follow Kotlin coding conventions: Clear naming, consistent formatting. Handle exceptions with
try-catchin control flow. Test with edge cases (e.g., empty ranges, invalid conditions).