Kotlin Exception Handling

An exception is an error that occurs at runtime. Instead of crashing the entire program, Kotlin lets you catch exceptions, respond to them, and continue execution. You surround risky code with a try block and handle problems in a catch block.

Basic try-catch

fun main() {
    try {
        val result = 10 / 0   // ArithmeticException!
        println(result)
    } catch (e: ArithmeticException) {
        println("Cannot divide by zero: ${e.message}")
    }
    println("Program continues normally")
}

Output:

Cannot divide by zero: / by zero
Program continues normally

try-catch-finally

fun readData(input: String): Int {
    try {
        return input.trim().toInt()
    } catch (e: NumberFormatException) {
        println("Not a valid number: '$input'")
        return -1
    } finally {
        println("readData() finished — always runs")
    }
}

fun main() {
    println(readData("42"))
    println(readData("abc"))
}

Output:

readData() finished — always runs
42
Not a valid number: 'abc'
readData() finished — always runs
-1

Multiple catch Blocks

fun process(input: String, index: Int) {
    try {
        val number = input.toInt()
        val items = listOf(10, 20, 30)
        println("Value at $index: ${items[index] / number}")
    } catch (e: NumberFormatException) {
        println("Input is not a number: $input")
    } catch (e: IndexOutOfBoundsException) {
        println("Index $index is out of range")
    } catch (e: ArithmeticException) {
        println("Division by zero!")
    }
}

fun main() {
    process("2", 1)     // 20/2 = 10
    process("abc", 1)   // not a number
    process("2", 10)    // out of range
    process("0", 1)     // divide by zero
}

try as an Expression

val value: Int = try {
    "123".toInt()
} catch (e: NumberFormatException) {
    -1
}

println(value)   // 123

val bad: Int = try {
    "abc".toInt()
} catch (e: NumberFormatException) {
    -1
}

println(bad)     // -1

Common Kotlin Exceptions


Exception                   │ Cause
────────────────────────────┼────────────────────────────────────
ArithmeticException         │ divide by zero
NullPointerException        │ using !! on null value
NumberFormatException       │ "abc".toInt()
IndexOutOfBoundsException   │ list[100] when list has 5 items
IllegalArgumentException    │ require() fails
IllegalStateException       │ check() fails
StackOverflowError          │ infinite recursion
ClassCastException          │ wrong cast (value as String when it is Int)

require and check

fun createUser(name: String, age: Int) {
    require(name.isNotBlank()) { "Name cannot be empty" }
    require(age in 0..120) { "Age must be 0–120, got $age" }

    var status = "pending"
    check(status == "pending") { "User already active" }

    println("User $name created, age $age")
}

fun main() {
    createUser("Alice", 30)     // OK
    createUser("", 25)          // throws IllegalArgumentException: Name cannot be empty
}

Handling Exceptions Gracefully with runCatching

val result = runCatching {
    "42".toInt()
}

println(result.isSuccess)          // true
println(result.getOrNull())        // 42
println(result.getOrDefault(-1))   // 42

val bad = runCatching { "abc".toInt() }
println(bad.isFailure)             // true
println(bad.exceptionOrNull()?.message)  // For input string: "abc"
println(bad.getOrDefault(-1))      // -1

Practical Example: Safe File Parser

fun parseConfig(lines: List): Map {
    val config = mutableMapOf()
    lines.forEachIndexed { lineNum, line ->
        try {
            val parts = line.split("=")
            require(parts.size == 2) { "Expected key=value format" }
            config[parts[0].trim()] = parts[1].trim()
        } catch (e: IllegalArgumentException) {
            println("Line ${lineNum + 1} skipped: ${e.message}")
        }
    }
    return config
}

fun main() {
    val input = listOf(
        "host = localhost",
        "port = 8080",
        "invalid line without equals",
        "debug = true"
    )

    val config = parseConfig(input)
    println(config)
}

Output:

Line 3 skipped: Expected key=value format
{host=localhost, port=8080, debug=true}

Leave a Comment

Your email address will not be published. Required fields are marked *