Kotlin runCatching Explained: A Cleaner Alternative to try-catch ?

3 min readApr 27, 2025

Handling errors gracefully is a fundamental skill in building reliable Kotlin applications.
Most developers start by using the familiar try-catch blocks — and while they work, they often lead to verbose, nested, and hard-to-read code.

Luckily, Kotlin offers a cleaner, more functional alternative: runCatching.
In this guide, we'll start from the basics and progressively dive deeper. By the end, you’ll know when and why runCatching is often the better choice.

Traditional Error Handling: try-catch

In Kotlin (and Java), we usually handle exceptions using try-catch blocks.

fun divide(a: Int, b: Int): Int {
return try {
a / b
} catch (e: ArithmeticException) {
println("Cannot divide by zero.")
0
}
}

fun main() {
println(divide(10, 2)) // Output: 5
println(divide(10, 0)) // Output: Cannot divide by zero. Then 0
}

While this works fine for small examples, it becomes increasingly bulky and error-prone as operations grow in complexity.

Introducing runCatching

Kotlin’s runCatching function provides a functional and fluent way to handle exceptions.
It wraps risky code inside a block and returns a Result object representing success or failure — without the need for explicit catch blocks.

A Simple Example

fun divide(a: Int, b: Int): Int {
return runCatching {
a / b
}.getOrElse {
println("Cannot divide by zero.")
0
}
}

fun main() {
println(divide(10, 2)) // Output: 5
println(divide(10, 0)) // Output: Cannot divide by zero. Then 0
}

Notice how the code is more concise and readable compared to traditional try-catch.

Understanding the Result Type

When you use runCatching, it returns a Result object that can be:

  • Success(value) — the operation completed successfully
  • Failure(exception) — the operation threw an exception

You can work with the result easily:

fun riskyOperation(): String {
if (Math.random() > 0.5) throw RuntimeException("Something went wrong!")
return "Success!"
}

fun main() {
val result = runCatching { riskyOperation() }

if (result.isSuccess) {
println("Yay! ${result.getOrNull()}")
} else {
println("Oops! ${result.exceptionOrNull()?.message}")
}
}

Scaling Up: Chaining Operations with runCatching

Real-world applications often require multiple operations that can fail.
runCatching shines here by letting you chain risky operations beautifully.

fun fetchDataFromServer(): String {
throw RuntimeException("Server not reachable")
}

fun parseData(data: String): Int {
return data.length
}

fun saveData(parsedData: Int) {
println("Saving data of length: $parsedData")
}

fun main() {
runCatching { fetchDataFromServer() }
.map { parseData(it) }
.onSuccess { saveData(it) }
.onFailure { println("Failed due to: ${it.message}") }
}

Instead of deeply nested try-catch blocks, you get a linear, readable flow of operations.

Bonus Tip: Recovering from Failures

You can also recover gracefully from a failure without throwing an error to your users.

val result = runCatching { "Kotlin".substring(10) } // Will throw

val finalResult = result.getOrDefault("Fallback value")

println(finalResult) // Output: Fallback value

Or using .recover() for more flexible recovery:

val finalResult = result.recover { throwable ->
"Recovered from error: ${throwable.message}"
}.getOrNull()

println(finalResult)

When Should You Prefer runCatching?

✅ When you want functional-style error handling.
✅ When you have multiple dependent risky operations.
✅ When you want to chain operations cleanly.
✅ When you prefer working with results instead of exceptions.
✅ When you need better readability and maintainability.

Final Thoughts

Traditional try-catch blocks are reliable but can quickly clutter your code.
Kotlin’s runCatching offers a more elegant, functional, and readable way to handle errors.

“If error handling is making your code messy, it’s a sign you should runCatching it.”

The next time you catch yourself writing nested try-catch blocks, pause and think:
"Can I solve this better with runCatching?"
Most often, the answer will be yes — and your codebase will thank you.

--

--

Responses (1)