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

The Result Type

The Result type is a box that either holds a successful answer or holds the error that happened instead, without ever throwing.
Syntax
kotlin
val result = runCatching { riskyCall() }

result.getOrNull()
result.getOrElse { default }
result.fold(
    onSuccess = { value -> /* ... */ },
    onFailure = { error -> /* ... */ }
)

Creating a Result with runCatching

runCatching { } executes a block of code and wraps the outcome in a Result: a caught exception becomes a failure, and a normal return value becomes a success.

Example: Creating a Result with runCatching

markup
// Entry point: execution of the program starts here
fun main() {
    // Declare a read-only variable `result`, set to `runCatching { "42".toInt() }`
    val result = runCatching { "42".toInt() }
    // Print "Success: ${result.isSuccess}" to the console, with a trailing newline
    println("Success: ${result.isSuccess}")
}

Extracting Values Safely

.getOrNull() returns the successful value or null on failure, while .getOrElse { } lets you supply a fallback computed from the failure itself.

Example: Extracting Values Safely

markup
// Entry point: execution of the program starts here
fun main() {
    // Declare a read-only variable `goodResult`, set to `runCatching { "42".toInt() }`
    val goodResult = runCatching { "42".toInt() }
    // Declare a read-only variable `badResult`, set to `runCatching { "abc".toInt() }`
    val badResult = runCatching { "abc".toInt() }
    // Print "Good: ${goodResult.getOrNull()}" to the console, with a trailing newline
    println("Good: ${goodResult.getOrNull()}")
    // Print "Bad with fallback: ${badResult.getOrElse { -1 }}" to the console, with a trailing newline
    println("Bad with fallback: ${badResult.getOrElse { -1 }}")
}

Handling Both Outcomes with fold

.fold(onSuccess, onFailure) lets you handle a success and a failure case together in one expression, producing a single unified result from either branch.

Example: Handling Both Outcomes with fold

markup
// Entry point: execution of the program starts here
fun main() {
    // Declare a read-only variable `result`, set to `runCatching { "abc".toInt() }`
    val result = runCatching { "abc".toInt() }
    val message = result.fold(
        onSuccess = { "Parsed: $it" },
        onFailure = { "Failed: ${it.message}" }
    )
    // Print `message` to the console, with a trailing newline
    println(message)
}

Result in Function Return Types

A function can return Result<T> directly instead of throwing, making failure an explicit, visible part of its return type that callers must consciously handle. (Declaring Result as an explicit function return type requires Kotlin 1.5+; on older versions the same value can still be computed and stored in a val, as shown below.)

Example: Result in Function Return Types

markup
// Entry point: execution of the program starts here
fun main() {
    // Declare a read-only variable `input`, set to `"-5"`
    val input = "-5"
    // Call `runCatching` with a trailing lambda, storing the result in `result`
    val result: Result<Int> = runCatching {
        // Declare a read-only variable `age`, set to `input.toInt()`
        val age = input.toInt()
        require(age >= 0) { "Age cannot be negative" }
        age
    }
    // Print `result.fold(onSuccess = { "Age: $it" }, onFailure = { "Invalid: ${it.message}" })` to the console, with a trailing newline
    println(result.fold(onSuccess = { "Age: $it" }, onFailure = { "Invalid: ${it.message}" }))
}
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. Forgetting Result is designed as a return-value alternative to exceptions, not a replacement for using try/catch when calling code that itself throws.
  2. Not checking .isSuccess/.isFailure (or using .fold/.getOrElse) and instead calling .getOrThrow() immediately, defeating the purpose of a non-throwing result.
  3. Assuming Result can hold any kind of computation state (like 'still loading'); it strictly represents success or failure, not other states.
Chapter Summary
  • Result<T> represents either a successful value or a failure, without needing a try/catch at the call site.
  • runCatching { } runs a block and wraps its outcome in a Result, catching any thrown exception into the failure case.
  • .getOrNull(), .getOrElse { }, and .getOrThrow() extract the value from a Result in different ways.
  • .fold(onSuccess, onFailure) handles both outcomes of a Result in a single expression.
🔒

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.