Given a Kotlin Result<T>, what are the differences between getOrNull(), getOrDefault(), getOrElse(), and getOrThrow() for extracting the value?
answer
- Null / Default / Else / Throw
- getOrDefault = eager arg; getOrElse = lazy lambda + sees exception
- getOrThrow re-throws the stored Throwable
- exceptionOrNull mirrors getOrNull
- Prefer getOrElse for expensive fallbacks
basics
~10 sAll four pull the success value out of a Result. getOrNull returns null on failure, getOrDefault returns a fallback you pass, getOrElse computes a fallback from the exception, and getOrThrow re-throws the failure's exception.
solid answer
~40 sThese are the terminal getters on Result<T>. getOrNull(): T? returns the value on success or null on failure. getOrDefault(defaultValue): T returns the value or an eagerly-evaluated default; the default is computed even on success because it's a plain argument. getOrElse { e -> ... }: T takes a lambda receiving the Throwable, so the fallback is lazy and can depend on the exception. getOrThrow(): T returns the value or re-throws the captured exception. Prefer getOrElse over getOrDefault when the fallback is expensive (lazy) or when you need the exception. getOrNull is for when failure simply means 'no value'. getOrThrow turns a Result back into normal exception flow, useful at a boundary where you've finished functional handling and want exceptions again.
code
kotlin · 8 linesval r: Result<Int> = runCatching { "7".toInt() }
val failing: Result<Int> = runCatching { "x".toInt() }
println(r.getOrNull()) // 7
println(failing.getOrNull()) // null
println(failing.getOrDefault(-1)) // -1 (eager)
println(failing.getOrElse { e -> e.message?.length ?: 0 }) // lazy, sees e
// failing.getOrThrow() // throws NumberFormatExceptiongo deeper
Can state each getter's return on success and failure and pick getOrNull vs getOrThrow correctly.
Articulates the eager-vs-lazy distinction between getOrDefault and getOrElse and that getOrElse receives the Throwable.
Discusses inline semantics, return-type widening to R, and when re-throwing via getOrThrow at a boundary is the right design.
Frames getter choice as part of an error-handling boundary strategy and reasons about API ergonomics of exposing Result vs unwrapping it.
## What is Result<T>? `Result<T>` is a value class in the Kotlin standard library representing either a successful value of type `T` or a failure carrying a `Throwable`. You inspect it with `isSuccess`/`isFailure` or, more commonly, with the consuming functions below. It is *not* a monad transformer or `Either` — it only ever holds a `Throwable` on the failure side. ## The four value getters - **`getOrNull(): T?`** — returns the value on success, or `null` on failure. The exception is discarded. Best when failure just means "absent". - **`getOrDefault(defaultValue: R): R`** — returns the value on success, otherwise the `defaultValue` argument. Because `defaultValue` is an ordinary parameter, it is **evaluated eagerly** (always computed, even when the Result is a success and the default is unused). - **`getOrElse(onFailure: (Throwable) -> R): R`** — returns the value on success, otherwise the result of calling `onFailure` with the captured `Throwable`. The lambda is **lazy** (only invoked on failure) and **has access to the exception**. It is `inline`, so the lambda body can do non-local returns from the enclosing function. - **`getOrThrow(): T`** — returns the value on success, otherwise **re-throws** the stored `Throwable`. This converts the Result back into ordinary exception-based control flow. ## Why getOrElse usually beats getOrDefault ```kotlin val r: Result<Int> = runCatching { compute() } // Eager: expensiveFallback() runs even on success val a = r.getOrDefault(expensiveFallback()) // Lazy: lambda runs only on failure, and sees the exception val b = r.getOrElse { e -> log.warn("compute failed: ${e.message}") -1 } ``` `getOrDefault` cannot see the exception and always evaluates its argument; `getOrElse` is lazy and exception-aware. Reach for `getOrDefault` only when the default is a cheap constant. ## Reading the exception `exceptionOrNull(): Throwable?` returns the captured throwable on failure or `null` on success — the mirror image of `getOrNull()`. Use it when you want the error rather than the value. ## Key keywords These are `inline` extension functions; `getOrElse` and `getOrDefault` widen the return type to `R` (a supertype of `T`), so the fallback may be of a broader type.
- If a Result is a success, does getOrDefault still evaluate its argument expression?Yes. The default is a normal eagerly-evaluated argument, so it is computed regardless and simply ignored on success. getOrElse avoids that by taking a lambda.
- How would you get the Throwable instead of the value?Use exceptionOrNull(): Throwable? — it returns the captured exception on failure or null on success.
getOrNull says 'nothing here', getOrDefault hands you a spare you prepared in advance, getOrElse builds a spare on demand after seeing what broke, getOrThrow just lets the original failure fly again.
saying these in an interview costs you the question
- Claiming getOrDefault evaluates its argument lazily
- Saying getOrElse cannot see the exception
- Thinking getOrThrow returns null on failure instead of throwing
- Confusing Result with Either / saying it can hold an arbitrary error type
- Believing getOrNull rethrows or logs the exception