skip to content

Result<T> & runCatching

runCatching captures a thrown exception into a Result instead of propagating it. The two caveats worth stating are that Result is discouraged in public return types, and that it swallows CancellationException, which breaks coroutine cancellation.

part ofKotlinoverview, primer and where to startread it →
on this pageshow

questions

5

What is Kotlin's Result<T> type and what does runCatching { } do?

level: juniorimportance: must knowfreq 60%

answer

  1. Success holds T, failure holds Throwable
  2. runCatching = try/catch that returns a Result
  3. getOrNull / exceptionOrNull / getOrThrow
  4. Result.success / Result.failure factories
  5. @JvmInline value class — cheap wrapper

basics

~10 s

Result<T> is a box that holds either a successful value or a failure with an exception. runCatching runs a block of code and returns success if it finishes, or failure if it throws.

solid answer

~30 s

Result<T> is a stdlib type that represents the outcome of an operation: either a success holding a value of type T, or a failure holding a Throwable. You create one with Result.success(value), Result.failure(throwable), or runCatching { }. runCatching executes the lambda and wraps a normal return in Result.success, or any thrown exception in Result.failure. You inspect it with isSuccess / isFailure, getOrNull(), exceptionOrNull(), or getOrThrow(). It lets you treat errors as values instead of letting exceptions propagate immediately, which is handy at boundaries where you want to defer or transform error handling.

code

kotlin · 8 lines
kotlin
fun readPort(raw: String): Result<Int> = runCatching {
    val n = raw.toInt()
    require(n in 1..65535) { "port out of range" }
    n
}

val ok = readPort("8080").getOrNull()        // 8080
val bad = readPort("99999").exceptionOrNull() // IllegalArgumentException

go deeper

for a junior

Knows Result is success-or-failure and runCatching wraps a try/catch into a returned value.

for a middle

Fluently uses getOrNull/getOrElse/exceptionOrNull and both runCatching forms, and knows the factory functions.

for a senior

Mentions Result is an inline value class and frames it as 'errors as values' for boundary code.

for a principal

Can position Result against exceptions and sealed-class result types and discuss API design implications.

## What Result<T> is `Result<T>` is a class in the Kotlin standard library (`kotlin.Result`) that encapsulates the outcome of an operation as a value. It is in exactly one of two states: - **Success** — holds a value of type `T`. - **Failure** — holds a `Throwable` (the exception that occurred). This turns error handling into data: instead of an exception unwinding the stack, you get back an object you can pass around, inspect, and transform. ## Creating a Result - `Result.success(value)` — wraps a value. - `Result.failure(throwable)` — wraps an exception. - `runCatching { ... }` — the most common factory. It runs the lambda; if it returns normally, you get `Result.success(returnValue)`; if it throws, you get `Result.failure(thrown)`. There is also a receiver form: `someObject.runCatching { ... }`, where `this` inside the block is `someObject`. ## Reading a Result - `isSuccess` / `isFailure` — booleans. - `getOrNull()` — the value, or `null` if failure. - `exceptionOrNull()` — the exception, or `null` if success. - `getOrThrow()` — the value, or re-throws the captured exception. - `getOrDefault(default)` / `getOrElse { e -> ... }` — value or a fallback. ```kotlin fun parse(text: String): Result<Int> = runCatching { text.toInt() } val r = parse("42") println(r.isSuccess) // true println(r.getOrNull()) // 42 val bad = parse("oops") println(bad.getOrNull()) // null println(bad.exceptionOrNull()) // java.lang.NumberFormatException println(bad.getOrDefault(-1)) // -1 ``` ## Why it is an inline value class `Result` is declared as a `@JvmInline value class`. At runtime there is usually no extra object allocation for the wrapper itself — the value or a small failure holder is used directly. This keeps it cheap. ## Key idea Result lets you **delay or relocate** the decision about what to do with an error: capture it now, decide later. That is its main purpose at code boundaries.

  • How do you get the value out while supplying a fallback if it failed?
    Use getOrElse { e -> fallback } or getOrDefault(value); getOrElse gives you the exception to branch on, getOrDefault just substitutes a constant.
  • What does getOrThrow() do on a failure?
    It re-throws the original captured Throwable, so you go back to ordinary exception-based control flow.

A Result is like a sealed envelope: open it and you find either the prize (value) or a note explaining what went wrong (exception).

saying these in an interview costs you the question

  • Thinking Result can hold both a value and an exception at once
  • Saying runCatching swallows errors silently with no way to retrieve them
  • Confusing Result<T> with a nullable T (null doesn't carry an exception)
  • Believing runCatching catches compile-time errors rather than runtime exceptions

context

open as a page

What is the cancellation hazard when using runCatching inside a coroutine, and how do you handle it correctly?

level: seniorimportance: must knowfreq 35%

basics

~10 s

runCatching catches every exception, including the special one that signals a coroutine was cancelled. Swallowing that breaks cancellation, so you must re-throw CancellationException instead of treating it like a normal failure.

open as a page

What is the difference between the top-level runCatching { } and the receiver form someObject.runCatching { }, and how do you read the captured exception?

level: middleimportance: should knowfreq 45%

basics

~10 s

Top-level runCatching just runs a block. The receiver form runs the block with a chosen object as 'this' inside it. Both return a Result; you read the error with exceptionOrNull() or getOrElse.

open as a page

When should you choose runCatching over a plain try/catch, and what are the trade-offs?

level: middleimportance: should knowfreq 38%

basics

~20 s

Use runCatching when you want the outcome as a value you can pass around, transform with map/fold, or chain. Use try/catch when you only need to react to specific exceptions in place. runCatching catches everything, which is sometimes too broad.

open as a page

Why is Result<T> discouraged as a public function return type, and what alternatives are recommended?

level: seniorimportance: should knowfreq 40%

basics

~20 s

Result is meant for internal capture, not as a return type. It is opaque about which errors can occur, it boxes when used generically, and the team that designed it advises returning your own success/failure type or throwing instead.

open as a page