Control Statements
Branching with if and when, iteration with loops, flow control with break/continue, and type-safe smart casts
Table of Contents
1if / else / else if
Kotlin's if is not only a statement — it can be an expression that returns a value. Use else if chains for multiple conditions, and omit braces for single-line branches when readability allows.
Classic if / else
if as an expression
When if returns a value, both branches must return compatible types. The result can be assigned to a variable:
Single-line if (no braces)
| Form | Example | Use when |
|---|---|---|
| if | if (x > 0) { ... } | Single condition |
| else if | else if (x > 10) { ... } | Multiple exclusive branches |
| if expression | val y = if (a) 1 else 2 | Assign result from branches |
Long else if chains are often clearer as a when expression — especially when matching constants, types, or ranges.
2when Expression
when replaces Java's switch. It is exhaustive-friendly, supports ranges and types, and can run with or without a subject argument.
when with a subject (like switch)
when without argument (if-else chain style)
Multiple conditions in one branch
when as expression with blocks
3for Loops
Kotlin has no C-style for (i = 0; i < n; i++). Use for (item in collection) or iterate over ranges and progressions.
Ranges — .., until, downTo, step
Collections and arrays
| Operator | Range | Notes |
|---|---|---|
.. | 1..5 | Inclusive both ends |
until | 1 until 5 | Includes start, excludes end |
downTo | 5 downTo 1 | Descending inclusive |
step | 0..10 step 2 | Custom increment |
Use for (i in list.indices) or list.withIndex() when you need the index. Prefer direct iteration when you only need values.
4while and do-while
while checks the condition before each iteration. do-while runs the body at least once, then checks the condition.
while loop
do-while loop
| Loop | Condition checked | Body runs at least once? |
|---|---|---|
while | Before iteration | No — may never run |
do { } while | After iteration | Yes — always runs once |
5break, continue, and Labels
break exits the nearest enclosing loop. continue skips to the next iteration. Use labels to target an outer loop in nested structures.
break and continue
Labeled break and continue
return@label in inline lambdas
6Smart Casts and Type Checks
Use is to check types, as for unsafe casts, and as? for safe casts. After a successful is check, Kotlin smart casts the variable in that scope.
is — type check
as and as? — explicit casts
Smart cast limitations
| Operator | Purpose | On failure |
|---|---|---|
is | Type check (Boolean) | N/A — returns false |
as | Unsafe cast | ClassCastException |
as? | Safe cast | Returns null |
| Smart cast | Auto-narrow type after is | Requires stable, non-mutable reference |
7Summary Cheatsheet
| Topic | Key Takeaway |
|---|---|
| if | Statement or expression: val x = if (a) 1 else 2 |
| when | Replaces switch; with/without subject; ranges, types, multiple values |
| for | for (x in collection); ranges: .., until, downTo, step |
| while / do-while | Condition-first vs body runs at least once |
| break / continue | Exit loop or skip iteration; use @label for outer loops |
| Type checks | is + smart cast; as unsafe; as? safe |
| Next lesson | Functions — parameters, return types, recursion |
Kotlin Control Statements MCQ Practice
10 Basic MCQs 10 Advanced MCQs10 Basic Control Flow MCQs
Which Kotlin construct replaces Java's switch statement?
when is Kotlin's powerful alternative to switch, supporting expressions, ranges, types, and multiple conditions per branch.In Kotlin, if can be used as?
val result = if (condition) a else b treats if as an expression — both branches must yield compatible types.What values does the range 1..5 include when used in a for loop?
.. operator creates a closed range — both the start and end values are included in iteration.What does 1 until 5 produce?
until creates a half-open range — it includes the start but excludes the end value (like many APIs use for indices).A when block without a subject argument is most similar to?
when { x > 0 -> ...; else -> ... } evaluates each branch condition like a series of if / else if checks.In a do-while loop, when is the condition evaluated?
do { ... } while (condition) executes the body first, then checks the condition — so the body always runs at least once.What does break@outer do in nested loops?
outer@ let you target a specific enclosing loop with break@outer or continue@outer.After if (x is String) in the same block, Kotlin automatically treats x as String. This is called?
is check.Which operator performs a safe cast that returns null on failure?
as? returns null instead of throwing ClassCastException when the cast is not possible.Which range expression counts from 5 down to 1 inclusive?
downTo creates a descending progression; .. always counts upward and cannot produce 5,4,3,2,1 directly.10 Advanced Control Flow MCQs
In when (x) { 1, 2 -> "low"; in 3..10 -> "mid"; else -> "high" }, what does the comma in 1, 2 mean?
when branch act like logical OR — the branch runs if x is 1 or 2.What does for (i in 0..10 step 2) print for i?
step sets the increment between values in a progression while keeping the range endpoints valid.What does continue do inside a loop?
continue jumps to the next loop iteration without executing remaining statements in the current pass.The is operator in Kotlin is used to?
x is String returns true if x is a String at runtime and enables smart casting in that branch.You need a loop that always runs its body at least once before checking the condition. Which do you use?
do-while guarantees one execution before the condition is tested — useful for input validation menus.What is the correct syntax to break out of a loop labeled search?
label@ on the loop and break@label / continue@label to control nested iteration.What happens when an unsafe cast obj as Int fails at runtime?
as performs an unchecked cast at runtime — failure throws ClassCastException. Use as? when failure should yield null.Smart casting often fails for a property declared as?
var properties because their type might change between the check and usage — copy to a local val instead.In for (i in 1..10 step 3), what is the role of step?
step n advances by n each iteration (e.g. 1, 4, 7, 10 for step 3 in 1..10).When when is used as an expression that returns a value, it must be?
when must assign a value on every path — use else or cover all enum/sealed cases so the compiler can verify exhaustiveness.Kotlin Control Statements Interview Q&A
15 topic-focused questions for interviews and revision.
if as a statement and if as an expression?easyif runs a branch for side effects only. As an expression, it returns a value: val max = if (a > b) a else b. Expression form requires both branches to return compatible types.when compare to Java's switch?easywhen supports arbitrary expressions, ranges (in 1..10), types (is String), multiple values per branch, and can be used with or without a subject. It is more flexible and idiomatic than classic switch... versus until in Kotlin ranges.easy1..5 is inclusive on both ends (1 through 5). 1 until 5 includes 1 but excludes 5, yielding 1–4. Use until when the end index should not be processed — common for zero-based length loops.downTo and step?mediumdownTo iterates descending (e.g. 10 downTo 1). step customizes increment size (e.g. 0..100 step 10 for every tenth value). Combine them: 100 downTo 0 step 10.while and do-while?easywhile evaluates the condition before the body — the body may never execute. do-while runs the body first, then checks the condition, guaranteeing at least one execution.break and continue work?mediumouter@ for (...). Use break@outer or continue@outer to affect that specific loop instead of only the innermost one — essential for nested search loops.is type check, the compiler automatically narrows the variable's type in that scope (e.g. call .length on a value checked as String) without an explicit as cast, when the reference is stable.var properties (another thread could change the type), custom getters the compiler cannot analyze, and when the variable is captured in a lambda that might run later. Copy to a local val after checking.as and as?.easyas is an unsafe cast — failure throws ClassCastException. as? is a safe cast returning null on failure, ideal for optional narrowing of platform types or mixed Any values.when replace a long else if chain? Give an example.mediumelse if branches, use when (score) { in 90..100 -> "A"; in 75..89 -> "B"; else -> "C" } or a subject-less when { score >= 90 -> ... } for boolean conditions.for (i = 0; i < n; i++) loop?easyfor (i in 0 until n) or for (i in 0..<n) (Kotlin 1.7+ range syntax where supported) or iterate collections directly with for (item in list).return@forEach mean inside a lambda?hardcontinue), not exiting main. The label matches the inline function name (forEach, run, etc.).when branch?easywhen (c) { 'a', 'e', 'i' -> "Vowel"; else -> "Consonant" }. You can also combine with ranges: in 1..3, 7 -> ... in advanced cases.if expression that assigns a grade letter from a numeric score.mediumval grade = when { score >= 90 -> "A"; score >= 75 -> "B"; else -> "C" } or nested if: val grade = if (score >= 90) "A" else if (score >= 75) "B" else "C".for (n in numbers) { if (n > 10 && n % 2 == 0) { println(n); break } } or numbers.first { it > 10 && it % 2 == 0 }. break exits once found; first is the idiomatic functional alternative.