Skip to content

Conditional Statements

Overview

Kotlin provides powerful conditional statements, including if expressions and when expressions. Unlike many other languages, conditional statements in Kotlin are expressions, meaning they can return values, making code more concise and functional.

if Expressions

Basic if Statement

kotlin
fun main() {
    val score = 85
    
    // Basic if statement
    if (score >= 60) {
        println("Passed!")
    }
    
    // if-else statement
    if (score >= 90) {
        println("Excellent")
    } else {
        println("Good")
    }
    
    // if-else if-else chain
    if (score >= 90) {
        println("Grade: A")
    } else if (score >= 80) {
        println("Grade: B")
    } else if (score >= 70) {
        println("Grade: C")
    } else if (score >= 60) {
        println("Grade: D")
    } else {
        println("Grade: F")
    }
}

if as an Expression

kotlin
fun main() {
    val score = 85
    
    // if expression returns a value
    val grade = if (score >= 90) {
        "A"
    } else if (score >= 80) {
        "B"
    } else if (score >= 70) {
        "C"
    } else if (score >= 60) {
        "D"
    } else {
        "F"
    }
    
    println("Grade: $grade")
    
    // Simplified if expression
    val status = if (score >= 60) "Pass" else "Fail"
    println("Exam status: $status")
    
    // Complex if expression
    val message = if (score >= 90) {
        val bonus = score - 90
        "Excellent! Bonus points: $bonus"
    } else {
        val needed = 90 - score
        "Need $needed more points to reach excellent"
    }
    
    println(message)
}

Practical Applications of Conditional Expressions

kotlin
fun main() {
    // Null check
    val name: String? = "Alice"
    val displayName = if (name != null) name else "Anonymous"
    println("Display name: $displayName")
    
    // Range check
    val temperature = 25
    val weather = if (temperature < 0) {
        "Freezing"
    } else if (temperature < 10) {
        "Cold"
    } else if (temperature < 20) {
        "Cool"
    } else if (temperature < 30) {
        "Warm"
    } else {
        "Hot"
    }
    println("Weather: $weather (${temperature}°C)")
    
    // Boolean logic
    val age = 20
    val hasLicense = true
    val canDrive = if (age >= 18 && hasLicense) {
        "Can drive"
    } else if (age < 18) {
        "Too young"
    } else {
        "Needs license"
    }
    println("Driving status: $canDrive")
}

when Expressions

Basic when Expression

kotlin
fun main() {
    val dayOfWeek = 3
    
    // Basic when expression
    when (dayOfWeek) {
        1 -> println("Monday")
        2 -> println("Tuesday")
        3 -> println("Wednesday")
        4 -> println("Thursday")
        5 -> println("Friday")
        6 -> println("Saturday")
        7 -> println("Sunday")
        else -> println("Invalid day")
    }
    
    // when as an expression
    val dayName = when (dayOfWeek) {
        1 -> "Monday"
        2 -> "Tuesday"
        3 -> "Wednesday"
        4 -> "Thursday"
        5 -> "Friday"
        6 -> "Saturday"
        7 -> "Sunday"
        else -> "Invalid"
    }
    
    println("Day: $dayName")
}

Advanced when Usage

kotlin
fun main() {
    val number = 15
    
    // Multiple value matching
    when (number) {
        1, 2, 3 -> println("Small number")
        4, 5, 6 -> println("Medium number")
        7, 8, 9 -> println("Larger number")
        else -> println("Other number")
    }
    
    // Range matching
    when (number) {
        in 1..10 -> println("Between 1 and 10")
        in 11..20 -> println("Between 11 and 20")
        in 21..30 -> println("Between 21 and 30")
        else -> println("Out of range")
    }
    
    // Type checking
    val obj: Any = "Hello"
    when (obj) {
        is String -> println("String: $obj, length: ${obj.length}")
        is Int -> println("Integer: $obj")
        is Boolean -> println("Boolean: $obj")
        else -> println("Unknown type")
    }
    
    // Condition expressions
    val score = 85
    when {
        score >= 90 -> println("Excellent")
        score >= 80 -> println("Good")
        score >= 70 -> println("Average")
        score >= 60 -> println("Pass")
        else -> println("Fail")
    }
}

Complex when Expression Applications

kotlin
enum class Color { RED, GREEN, BLUE, YELLOW, ORANGE, PURPLE }

fun mixColors(color1: Color, color2: Color): String {
    return when (setOf(color1, color2)) {
        setOf(Color.RED, Color.YELLOW) -> "Orange"
        setOf(Color.YELLOW, Color.BLUE) -> "Green"
        setOf(Color.BLUE, Color.RED) -> "Purple"
        else -> "Unknown mixed color"
    }
}

fun getColorInfo(color: Color): String {
    return when (color) {
        Color.RED -> {
            val wavelength = 700
            "Red - Wavelength: ${wavelength}nm"
        }
        Color.GREEN -> {
            val wavelength = 550
            "Green - Wavelength: ${wavelength}nm"
        }
        Color.BLUE -> {
            val wavelength = 450
            "Blue - Wavelength: ${wavelength}nm"
        }
        else -> "Other color"
    }
}

fun main() {
    println("Color mixing:")
    println(mixColors(Color.RED, Color.YELLOW))
    println(mixColors(Color.BLUE, Color.YELLOW))
    
    println("\nColor info:")
    println(getColorInfo(Color.RED))
    println(getColorInfo(Color.GREEN))
}

Nested Conditional Statements

Complex Conditional Logic

kotlin
data class User(val name: String, val age: Int, val isVip: Boolean, val balance: Double)

fun checkAccess(user: User, requestedAmount: Double): String {
    return if (user.age >= 18) {
        if (user.isVip) {
            if (user.balance >= requestedAmount) {
                "VIP user, transaction approved"
            } else {
                "VIP user, insufficient balance, but can overdraft"
            }
        } else {
            if (user.balance >= requestedAmount) {
                "Regular user, transaction approved"
            } else {
                "Regular user, insufficient balance"
            }
        }
    } else {
        "Minor user, requires guardian consent"
    }
}

// Refactoring nested if using when
fun checkAccessImproved(user: User, requestedAmount: Double): String {
    return when {
        user.age < 18 -> "Minor user, requires guardian consent"
        user.isVip && user.balance >= requestedAmount -> "VIP user, transaction approved"
        user.isVip && user.balance < requestedAmount -> "VIP user, insufficient balance, but can overdraft"
        !user.isVip && user.balance >= requestedAmount -> "Regular user, transaction approved"
        else -> "Regular user, insufficient balance"
    }
}

fun main() {
    val users = listOf(
        User("Alice", 25, true, 1000.0),
        User("Bob", 17, false, 500.0),
        User("Charlie", 30, false, 100.0),
        User("Diana", 28, true, 50.0)
    )
    
    val requestAmount = 200.0
    
    println("Access check results:")
    users.forEach { user ->
        val result = checkAccessImproved(user, requestAmount)
        println("${user.name}: $result")
    }
}

Best Practices for Conditional Statements

1. Prefer when Over Complex if-else Chains

kotlin
// Not recommended: Complex if-else chain
fun getGradeBad(score: Int): String {
    if (score >= 90) {
        return "A"
    } else if (score >= 80) {
        return "B"
    } else if (score >= 70) {
        return "C"
    } else if (score >= 60) {
        return "D"
    } else {
        return "F"
    }
}

// Recommended: Use when expression
fun getGradeGood(score: Int): String = when {
    score >= 90 -> "A"
    score >= 80 -> "B"
    score >= 70 -> "C"
    score >= 60 -> "D"
    else -> "F"
}

fun main() {
    val score = 85
    println("Grade: ${getGradeGood(score)}")
}

2. Leverage Smart Casts

kotlin
fun processValue(value: Any?) {
    when (value) {
        null -> println("Value is null")
        is String -> {
            // Smart cast: value is automatically cast to String
            println("String value: '$value', length: ${value.length}")
            if (value.isNotEmpty()) {
                println("First character: ${value[0]}")
            }
        }
        is Int -> {
            // Smart cast: value is automatically cast to Int
            println("Integer value: $value")
            if (value > 0) {
                println("Positive")
            } else if (value < 0) {
                println("Negative")
            } else {
                println("Zero")
            }
        }
        is List<*> -> {
            // Smart cast: value is automatically cast to List
            println("List value: $value, size: ${value.size}")
        }
        else -> println("Unknown type: ${value::class.simpleName}")
    }
}

fun main() {
    val values = listOf("Hello", 42, null, listOf(1, 2, 3), 3.14)
    values.forEach { processValue(it) }
}

3. Use Expressions Instead of Statements

kotlin
// Not recommended: Using statements
fun getStatusBad(isOnline: Boolean, hasMessages: Boolean): String {
    var status: String
    if (isOnline) {
        if (hasMessages) {
            status = "Online - New messages"
        } else {
            status = "Online"
        }
    } else {
        status = "Offline"
    }
    return status
}

// Recommended: Use expressions
fun getStatusGood(isOnline: Boolean, hasMessages: Boolean): String {
    return when {
        isOnline && hasMessages -> "Online - New messages"
        isOnline -> "Online"
        else -> "Offline"
    }
}

// Even more concise
fun getStatusBest(isOnline: Boolean, hasMessages: Boolean) = when {
    isOnline && hasMessages -> "Online - New messages"
    isOnline -> "Online"
    else -> "Offline"
}

fun main() {
    println(getStatusBest(true, true))
    println(getStatusBest(true, false))
    println(getStatusBest(false, false))
}

Practical Examples

User Permission System

kotlin
enum class Role { ADMIN, MODERATOR, USER, GUEST }
enum class Permission { READ, WRITE, DELETE, MANAGE_USERS }

data class UserAccount(val name: String, val role: Role, val isActive: Boolean)

class PermissionChecker {
    fun hasPermission(user: UserAccount, permission: Permission): Boolean {
        if (!user.isActive) return false
        
        return when (user.role) {
            Role.ADMIN -> true  // Admin has all permissions
            Role.MODERATOR -> when (permission) {
                Permission.READ, Permission.WRITE, Permission.DELETE -> true
                Permission.MANAGE_USERS -> false
            }
            Role.USER -> when (permission) {
                Permission.READ, Permission.WRITE -> true
                Permission.DELETE, Permission.MANAGE_USERS -> false
            }
            Role.GUEST -> permission == Permission.READ
        }
    }
    
    fun getAccessLevel(user: UserAccount): String {
        return when {
            !user.isActive -> "Account disabled"
            user.role == Role.ADMIN -> "Full access"
            user.role == Role.MODERATOR -> "Moderator access"
            user.role == Role.USER -> "Standard user access"
            user.role == Role.GUEST -> "Read-only access"
            else -> "Unknown access level"
        }
    }
}

fun main() {
    val users = listOf(
        UserAccount("Admin", Role.ADMIN, true),
        UserAccount("Moderator", Role.MODERATOR, true),
        UserAccount("User", Role.USER, true),
        UserAccount("Guest", Role.GUEST, true),
        UserAccount("Banned", Role.USER, false)
    )
    
    val checker = PermissionChecker()
    
    println("Permission check results:")
    users.forEach { user ->
        println("\n${user.name} (${user.role}):")
        println("  Access level: ${checker.getAccessLevel(user)}")
        Permission.values().forEach { permission ->
            val hasAccess = checker.hasPermission(user, permission)
            println("  $permission: ${if (hasAccess) "✓" else "✗"}")
        }
    }
}

Calculator Application

kotlin
enum class Operation { ADD, SUBTRACT, MULTIPLY, DIVIDE, POWER, MODULO }

class Calculator {
    fun calculate(a: Double, b: Double, operation: Operation): Result<Double> {
        return when (operation) {
            Operation.ADD -> Result.success(a + b)
            Operation.SUBTRACT -> Result.success(a - b)
            Operation.MULTIPLY -> Result.success(a * b)
            Operation.DIVIDE -> {
                if (b != 0.0) {
                    Result.success(a / b)
                } else {
                    Result.failure(ArithmeticException("Division by zero"))
                }
            }
            Operation.POWER -> Result.success(kotlin.math.pow(a, b))
            Operation.MODULO -> {
                if (b != 0.0) {
                    Result.success(a % b)
                } else {
                    Result.failure(ArithmeticException("Modulo by zero"))
                }
            }
        }
    }
    
    fun getOperationSymbol(operation: Operation): String = when (operation) {
        Operation.ADD -> "+"
        Operation.SUBTRACT -> "-"
        Operation.MULTIPLY -> "*"
        Operation.DIVIDE -> "/"
        Operation.POWER -> "^"
        Operation.MODULO -> "%"
    }
}

fun main() {
    val calculator = Calculator()
    val testCases = listOf(
        Triple(10.0, 5.0, Operation.ADD),
        Triple(10.0, 3.0, Operation.SUBTRACT),
        Triple(4.0, 3.0, Operation.MULTIPLY),
        Triple(15.0, 3.0, Operation.DIVIDE),
        Triple(15.0, 0.0, Operation.DIVIDE),  // Error case
        Triple(2.0, 3.0, Operation.POWER),
        Triple(17.0, 5.0, Operation.MODULO)
    )
    
    println("Calculator test:")
    testCases.forEach { (a, b, op) ->
        val symbol = calculator.getOperationSymbol(op)
        val result = calculator.calculate(a, b, op)
        
        when {
            result.isSuccess -> {
                val value = result.getOrNull()
                println("$a $symbol $b = $value")
            }
            result.isFailure -> {
                val error = result.exceptionOrNull()
                println("$a $symbol $b = Error: ${error?.message}")
            }
        }
    }
}

Performance Considerations

when Expression Optimization

kotlin
// Compiler optimizes when expressions
fun optimizedWhen(value: Int): String {
    return when (value) {
        1, 2, 3, 4, 5 -> "Small number"  // Compiler may generate jump table
        in 6..10 -> "Medium number"
        in 11..100 -> "Large number"
        else -> "Very large number"
    }
}

// For enums, compiler generates efficient code
enum class Status { PENDING, PROCESSING, COMPLETED, FAILED }

fun getStatusMessage(status: Status): String = when (status) {
    Status.PENDING -> "Waiting to process"
    Status.PROCESSING -> "Processing"
    Status.COMPLETED -> "Completed"
    Status.FAILED -> "Failed"
}

Next Steps

After mastering conditional statements, let's learn about loop statements in Kotlin, including for loops and while loops.

Next Chapter: Loops

Exercises

  1. Create a grading system that assigns grades and comments based on scores
  2. Implement a simple state machine using when expressions for state transitions
  3. Write a function to determine if a year is a leap year
  4. Design a game character class system that assigns different skills based on class
  5. Create a smart recommendation system that recommends content based on user preferences

Content is for learning and research only.