← Back to Kotlin Course | Chapter 13: Error Handling & Testing | Lesson 1 of 6

try, catch, finally

try, catch, and finally let your program attempt something risky, recover if it goes wrong, and still clean up afterward no matter what happened.
Syntax
kotlin
try {
    // risky code
} catch (e: ExceptionType) {
    // handle it
} catch (e: OtherException) {
    // handle differently
} finally {
    // always runs
}

Catching an Exception

Wrapping risky code in try { } followed by catch (e: ExceptionType) { } lets the program recover gracefully instead of crashing when that specific kind of exception occurs.

Example: Catching an Exception

markup
// Entry point: execution of the program starts here
fun main() {
    try {
        // Declare a read-only variable `result`, set to `10 / 0`
        val result = 10 / 0
        // Print `result` to the console, with a trailing newline
        println(result)
    } catch (e: ArithmeticException) {
        // Print "Caught an error: ${e.message}" to the console, with a trailing newline
        println("Caught an error: ${e.message}")
    }
}

Using finally for Cleanup

A finally { } block always executes after the try/catch, regardless of whether an exception was thrown or caught, making it the right place for cleanup code that must always run.

Example: Using finally for Cleanup

markup
// Entry point: execution of the program starts here
fun main() {
    try {
        // Print "Attempting risky operation" to the console, with a trailing newline
        println("Attempting risky operation")
        throw RuntimeException("Something failed")
    } catch (e: RuntimeException) {
        // Print "Handled: ${e.message}" to the console, with a trailing newline
        println("Handled: ${e.message}")
    } finally {
        // Print "Cleanup always runs" to the console, with a trailing newline
        println("Cleanup always runs")
    }
}

Multiple catch Blocks

Several catch blocks can be chained to handle different exception types differently, and Kotlin checks them in the order they are written, using the first matching type.

Example: Multiple catch Blocks

markup
// Entry point: execution of the program starts here
fun main() {
    // Declare a read-only variable `values`, set to `listOf("10", "abc", "5")`
    val values = listOf("10", "abc", "5")
    // Loop over `values`, binding each item to `value`
    for (value in values) {
        try {
            // Print "Parsed: ${value.toInt()}" to the console, with a trailing newline
            println("Parsed: ${value.toInt()}")
        } catch (e: NumberFormatException) {
            // Print "Not a number: $value" to the console, with a trailing newline
            println("Not a number: $value")
        }
    }
}

try as an Expression

Because try can be used as an expression, the value from whichever branch executes -- try or catch -- can be assigned directly to a variable.

Example: try as an Expression

markup
// Define the function `parseOrDefault` taking `text` and returning an Int
fun parseOrDefault(text: String): Int {
    // Return `try {` from this function
    return try {
        text.toInt()
    } catch (e: NumberFormatException) {
        -1
    }
}

// Entry point: execution of the program starts here
fun main() {
    // Print `parseOrDefault("42")` to the console, with a trailing newline
    println(parseOrDefault("42"))
    // Print `parseOrDefault("oops")` to the console, with a trailing newline
    println(parseOrDefault("oops"))
}
Related Topics
{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
Common Mistakes
  1. Catching a very broad type like Exception everywhere, hiding bugs that should have been fixed rather than silently swallowed.
  2. Forgetting that finally always runs, even if the try or catch block returns early, which is exactly the point of using it for cleanup.
  3. Not realizing try can be used as an expression, producing a value from whichever branch actually ran.
Chapter Summary
  • try { } wraps code that might throw an exception; catch (e: Type) { } handles a specific exception type if one occurs.
  • finally { } always runs after the try/catch, whether or not an exception was thrown, making it ideal for cleanup.
  • Multiple catch blocks can handle different exception types differently, checked in order from top to bottom.
  • try can be used as an expression, with the resulting value coming from whichever branch (try or catch) actually executed.
🔒

Chapter Quiz — Complete all 6 topics to unlock

0/6 topics done

Complete these topics first:

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.