Kotlin Try Catch Statement

Kotlin try and catch statements handle exceptions that occur while a program is running. Place code that may fail inside a try block and handle the expected exception in a following catch block.

If an exception is not handled, it propagates to the calling code and may terminate the current operation or program. Exception handling lets the application respond appropriately, report the failure, release resources, or continue when recovery is possible.

Kotlin Try-Catch Syntax

The following is the basic syntax of a try-catch block in Kotlin.

</>
Copy
 try {
   //code that code potentially throw and exception
 } catch(e: Some_Exception) {
   //code to handle if this exception is occurred
 } catch(e: Exception) {
   //you can have multiple catch blocks
   //code to handle if this exception is occurred
 }

A try-catch construct contains one try block and one or more catch blocks. Each catch parameter identifies the type of exception handled by that block. When an exception occurs, Kotlin selects the first compatible catch block.

Place specific exception types before general types such as Exception. A general catch placed first would also match its subclasses and prevent the more specific handlers from being reached.

Kotlin Try-Catch Example with Division by Zero

This example performs integer division by zero. The division throws an ArithmeticException, and the catch block handles it.

Kotlin Program – example.kt

</>
Copy
fun main(args: Array<String>) {
    val a = 6
    val b = 0
    var c : Int

    try {
        c = a/b
    } catch (e : Exception){
        println("Exception is handled.")
    }
}

Output

Exception is handled.

The catch parameter has the type Exception. It therefore handles ArithmeticException and other subclasses of Exception. It does not literally handle every possible Throwable, such as serious JVM errors that are outside the Exception hierarchy.

After the exception is caught, execution continues with the first statement after the complete try-catch construct. Statements remaining in the try block after the failing expression are skipped.

Catch a Specific Exception in Kotlin

Catch the most specific exception that the code can reasonably handle. Examples include ArithmeticException for invalid integer arithmetic, NumberFormatException for invalid numeric text, and IOException for input or output failures.

In the following example, the catch block handles only an ArithmeticException.

Kotlin Program – example.kt

</>
Copy
fun main(args: Array<String>) {
    val a = 6
    val b = 0
    var c : Int

    try {
        c = a/b
    } catch (e : ArithmeticException){
        println("a is $a and b is $b. a/b ?? You cannot divide something with zero.")
    }
}

Output

a is 6 and b is 0. a/b ?? You cannot divide something with zero.

If the try block throws an exception that is not an ArithmeticException or its subclass, this catch block does not handle it. The exception propagates to the caller unless another compatible catch block follows.

Read a Kotlin Exception Stack Trace

A stack trace identifies the exception type and the sequence of method calls leading to the failure. It is useful during debugging because it usually includes the source file and line where the exception occurred.

The exception object passed to a catch block provides the printStackTrace() method.

Kotlin Program – example.kt

</>
Copy
fun main(args: Array<String>) {
    val a = 6
    val b = 0
    var c : Int

    try {
        c = a/b
    } catch (e : Exception){
        e.printStackTrace()
    }
}

Output

java.lang.ArithmeticException: / by zero
	at exception_handling.ChangeValKt.main(ChangeVal.kt:8)

The first line reports an ArithmeticException. The next line identifies the function, source file, and line associated with the division. Exact stack-trace details can vary with the file name, package, compiler, and runtime environment.

Access the Exception Message in Kotlin

The nullable message property contains the detail message supplied by the exception. Because the property has the type String?, a message is not guaranteed to be present.

Kotlin Program – example.kt

</>
Copy
fun main(args: Array<String>) {
    val a = 6
    val b = 0
    var c : Int

    try {
        c = a/b
    } catch (e : ArithmeticException){
        println(e.message)
    }
}

Output

/ by zero

When displaying an error to a user, provide a clear application-specific message instead of relying on the technical exception message. The original exception can still be logged for diagnosis.

Kotlin Try-Catch with Multiple Exception Types

A try block can be followed by multiple catch blocks when failures require different responses. Kotlin checks the catch blocks from top to bottom and executes only the first matching block.

The following Kotlin program includes separate handlers for IOException and the more general Exception type.

Kotlin Program – example.kt

</>
Copy
import java.io.IOException

fun main(args: Array<String>) {
    val a = 6
    val b = 0
    var c : Int

    try {
        c = a/b
        print(c)
    } catch (e : IOException){
        println("An IOException occurred. Please Handle.")
    } catch (e : Exception){
        println("An Exception occurred. Handle.")
    }
}

Run this program and observe the output.

Output

An Exception occurred. Handle.

Process finished with exit code 0

The division throws an ArithmeticException. It does not match the first IOException handler, so Kotlin checks the next catch block. Because ArithmeticException is an Exception, the second catch block executes.

Kotlin does not use Java-style multi-catch syntax such as catch (e: IOException | SQLException). Use separate catch blocks when the exception types need distinct handling. If several types require identical handling, catch a meaningful common superclass where doing so does not hide unrelated failures.

Kotlin Try-Catch-Finally for Cleanup

A finally block runs after the try and catch processing, whether the try block completes normally or throws an exception. It is commonly used for cleanup that must occur on both paths.

</>
Copy
try {
    // Code that may throw an exception
} catch (e: SomeException) {
    // Handle the expected exception
} finally {
    // Cleanup that should always be attempted
}

The following example shows that finally executes after a failed conversion has been handled.

</>
Copy
fun main() {
    try {
        val number = "Kotlin".toInt()
        println(number)
    } catch (e: NumberFormatException) {
        println("The text is not a valid integer.")
    } finally {
        println("Conversion attempt finished.")
    }
}

Output

The text is not a valid integer.
Conversion attempt finished.

Abrupt process termination can prevent normal cleanup, so finally should not be treated as a guarantee under every possible runtime failure. Also avoid returning or throwing a new exception from finally, because doing so can hide the original result or failure.

Kotlin Try-Finally Without a Catch Block

Kotlin permits try with finally and no catch block. Use this form when the current function must perform cleanup but should allow the original exception to propagate to its caller.

</>
Copy
fun processTask() {
    println("Starting task")

    try {
        error("Task failed")
    } finally {
        println("Releasing task resources")
    }
}

Here, the cleanup message is printed and the IllegalStateException created by error() continues to the caller.

Use Kotlin Try-Catch as an Expression

In Kotlin, try is an expression and can produce a value. The value of the selected try or catch branch becomes the result. A finally block does not determine that result.

</>
Copy
fun parsePort(text: String): Int {
    return try {
        text.toInt()
    } catch (e: NumberFormatException) {
        8080
    }
}

fun main() {
    println(parsePort("9000"))
    println(parsePort("invalid"))
}

Output

9000
8080

This form is useful when a failed operation has a clear fallback value. If a fallback could hide invalid data or an operational problem, propagate the exception or return an explicit result type instead.

Throw a Custom Exception in Kotlin

Use throw when a function detects an invalid state or input that it cannot handle. Like try, throw is an expression in Kotlin.

</>
Copy
fun calculatePrice(quantity: Int): Int {
    if (quantity < 0) {
        throw IllegalArgumentException("Quantity cannot be negative")
    }
    return quantity * 50
}

fun main() {
    try {
        println(calculatePrice(-2))
    } catch (e: IllegalArgumentException) {
        println(e.message ?: "Invalid quantity")
    }
}

Output

Quantity cannot be negative

Standard exception types are suitable when they accurately describe the failure. A project can define a custom exception class when callers need to distinguish a domain-specific failure.

</>
Copy
class InvalidOrderException(message: String) : Exception(message)

Kotlin Try-With-Resources Alternative Using use()

Kotlin does not use Java’s try-with-resources syntax. For a compatible closeable resource, use the use() function. It closes the resource when the block finishes normally or with an exception.

</>
Copy
import java.io.File

fun readFirstLine(file: File): String? {
    return file.bufferedReader().use { reader ->
        reader.readLine()
    }
}

Prefer use() for streams, readers, writers, and similar resources instead of manually calling close() in several execution paths.

Kotlin Try-Catch Compared with runCatching()

The standard-library runCatching() function executes a block and represents its success or failure as a Result. It can be useful when an API should pass a result through transformations instead of handling it immediately with catch blocks.

</>
Copy
fun main() {
    val result = runCatching {
        "42".toInt()
    }

    result
        .onSuccess { value -> println("Value: $value") }
        .onFailure { error -> println("Failed: ${error.message}") }
}

Output

Value: 42

Use try-catch when control flow and exception-specific recovery are clearer as direct statements. Use Result operations when a failure needs to be returned, transformed, or composed. Do not use either approach to silently discard failures.

Checked and Unchecked Exceptions in Kotlin

Kotlin does not require functions to declare checked exceptions or force callers to catch them. This differs from Java source code, where some exception types must be caught or declared. Kotlin code can still catch Java exceptions such as IOException when recovery is appropriate.

When a Kotlin function is called from Java and its exception contract must be visible to Java, the @Throws annotation can generate the corresponding throws declaration.

</>
Copy
import java.io.IOException

@Throws(IOException::class)
fun loadConfiguration() {
    throw IOException("Configuration file is unavailable")
}

Kotlin Exception-Handling Practices

  • Catch an exception only where the code can recover, add useful context, translate it, or report it appropriately.
  • Catch specific exception types instead of using Exception for every failure.
  • Keep the try block focused on the operation that can fail.
  • Do not leave a catch block empty or ignore an exception without a documented reason.
  • Preserve the original exception as the cause when wrapping it in another exception.
  • Use use() for closeable resources and finally for other necessary cleanup.
  • Do not catch serious JVM errors merely to keep the application running.
  • Avoid displaying stack traces or internal exception details directly to application users.

Kotlin Try-Catch FAQs

Can Kotlin try-catch return a value?

Yes. A try-catch construct is an expression in Kotlin. The final expression in the executed try or catch branch becomes its value, allowing the result to be assigned or returned directly.

Can Kotlin use try-finally without catch?

Yes. A try block may be followed by finally without a catch block. The finally block performs cleanup, and any exception from the try block continues to propagate.

How do I catch multiple exceptions in Kotlin?

Add multiple catch blocks and order them from the most specific exception type to the most general. Kotlin executes the first compatible catch block.

What is the Kotlin alternative to try-with-resources?

Use the use() extension with a compatible closeable resource. It closes the resource after the block completes, including when the block throws an exception.

When should I use runCatching instead of try-catch?

Use runCatching() when success or failure should be represented as a Result and passed through result operations. Use try-catch when direct, exception-specific recovery makes the control flow easier to understand.

Kotlin Try-Catch Tutorial QA Checklist

  • Every catch block identifies an exception that the associated try block can reasonably produce.
  • Specific Kotlin exception handlers appear before general Exception handlers.
  • Examples distinguish exception handling from silently ignoring a failure.
  • The finally explanation does not claim that it determines the value of a try expression.
  • Resource-management examples use use() where appropriate.
  • The tutorial explains that Kotlin does not enforce checked exceptions.
  • Stack-trace and exception-message examples are presented as diagnostic information rather than user-facing error text.
  • The runCatching() example preserves failure information through Result.

Kotlin Try-Catch Summary

In this Kotlin Tutorial, we learned how to write try-catch and try-catch-finally constructs, catch specific or multiple exceptions, inspect exception messages and stack traces, return a value from a try expression, throw an exception, close resources with use(), and represent failures with runCatching().