Skip to Content
Course content

6: Control Flow Statements

Click on the "Edit" button in the top corner of the screen to edit your slide content.

I've spent a lot of time reviewing code from developers moving to Kotlin from Java or C#, and there is one specific pattern that almost everyone trips over in their first week. It usually looks something like this:

enum class OrderStatus { PENDING, SHIPPED, DELIVERED, CANCELLED }

fun getStatusMessage(status: OrderStatus): String {
    return when (status) {
        OrderStatus.PENDING -> "Your order is being prepared."
        OrderStatus.SHIPPED -> "Your order is on its way!"
        OrderStatus.DELIVERED -> "Package arrived!"
    }
}

If you try to compile this, the IDE is going to scream at you. You'll see an error saying 'when' expression must be exhaustive. The developer who wrote this probably thought, "I handled the three main states, the cancelled ones don't need a message," or they simply forgot about the CANCELLED state. In other languages, a switch statement might just do nothing if no case matches. Kotlin is different.

The Exhaustiveness Requirement

When you use when as an expression—meaning you are returning its result or assigning it to a variable—Kotlin forces you to cover every single possible outcome. It’s a safety feature. It prevents that nightmare scenario where you add a new status to your enum six months from now, forget to update this function, and your app crashes or returns null in production.

To fix this, you have two choices. You can explicitly handle the missing case, or use an else block as a catch-all:

fun getStatusMessage(status: OrderStatus): String {
    return when (status) {
        OrderStatus.PENDING -> "Your order is being prepared."
        OrderStatus.SHIPPED -> "Your order is on its way!"
        OrderStatus.DELIVERED -> "Package arrived!"
        OrderStatus.CANCELLED -> "Your order was cancelled." 
        // Or just use: else -> "Unknown status"
    }
}

Treating 'if' as a Value

One thing I love about Kotlin is that almost everything is an expression. In many languages, if is a statement—it performs an action. In Kotlin, if can return a value. You'll see a lot of legacy-style code that looks like this:

var message: String
if (isLoggedIn) {
    message = "Welcome back!"
} else {
    message = "Please log in."
}

That's way too much boilerplate. Since if returns a value, you can assign it directly to a val. I highly recommend doing this whenever possible because it lets you keep your variables immutable, which makes your code much easier to reason about:

val message = if (isLoggedIn) "Welcome back!" else "Please log in."

The Versatility of 'when'

Beyond just replacing switch statements, when is incredibly flexible. You aren't limited to checking a single variable against constants. You can check types, ranges, or even use it without an argument at all to replace a long chain of if-else if blocks.

Check this out:

fun describeScore(score: Int) = when {
    score >= 90 -> "A"
    score >= 80 -> "B"
    score in 70..79 -> "C"
    else -> "F"
}

Notice how I used in 70..79? That's a range check. It's clean, readable, and eliminates the need for those clunky && operators.

Iterating with Ranges and Steps

For loops in Kotlin are fundamentally different from the for(int i=0; i<10; i++) syntax you might be used to. We iterate over things: ranges, collections, or arrays.

  • The Inclusive Range: for (i in 1..5) runs from 1 to 5.
  • The Exclusive Range: for (i in 1 until 5) runs from 1 to 4. This is the one you'll use most often when iterating through indices of a list.
  • Counting Down: for (i in 5 downTo 1) does exactly what it says.
  • Custom Steps: for (i in 1..10 step 2) will give you 1, 3, 5, 7, 9.

I usually suggest using until for list indices to avoid the dreaded IndexOutOfBoundsException.

While and Do-While Loops

While loops in Kotlin are pretty standard. The while loop checks the condition first; if it's false, the block never runs. The do-while loop ensures the block runs at least once before checking the condition. You won't use these as often as for loops or when expressions, but they're essential for scenarios where you don't know exactly how many iterations you need—like polling an API until a certain status is reached.




📋 Practical Task

Build a Tiered Shipping Calculator

You are building a shipping module for an e-commerce app. Your task is to create a function called calculateShippingCost that determines the cost of shipping based on two factors: the orderValue (Double) and the membershipLevel (String: "GOLD", "SILVER", or "BRONZE").

Implement the following logic using when and if expressions:

  • GOLD members: Always get free shipping (0.0), regardless of order value.
  • SILVER members: Free shipping if the order value is over $50.0, otherwise they pay $5.0.
  • BRONZE members: Free shipping if the order value is over $100.0, otherwise they pay $10.0.
  • Unknown membership: If the membership string doesn't match the three levels above, charge a flat rate of $15.0.

Requirements:

  1. Use a when expression to handle the membership levels.
  2. Use an if expression inside the SILVER and BRONZE branches to handle the value threshold.
  3. Ensure the function returns a Double.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.