avatarGabriel Shanahan

Free AI web copilot to create summaries, insights and extended knowledge, download it at here

5739

Abstract

ode> is a success, and <code>onFailure(this.exceptionOrNull()!!)</code> otherwise.</p><h1 id="1e68">Retrieving a value</h1><h2 id="82b3">getOrThrow()</h2><div id="3fde"><pre><span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-type"><T></span> Result<span class="hljs-type"><T></span>.<span class="hljs-title">getOrThrow</span><span class="hljs-params">()</span></span>: T</pre></div><p id="5b2e">Returns the success value, or throws. While this might seem like a trivial function, it is actually incredibly useful when composing methods that return <code>Result</code>s, and the subject is interesting enough that we'll dedicate a separate section to it bellow.</p><p id="54e5">Equivalent to <code>fold({ it }, { throw it })</code>.</p><h2 id="2daa">getOrElse(), getOrDefault()</h2><div id="dbb5"><pre><span class="hljs-keyword">inline</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-type"><T, R></span> Result<span class="hljs-type"><T></span>.<span class="hljs-title">getOrElse</span><span class="hljs-params">( onFailure: (<span class="hljs-type">exception</span>: <span class="hljs-type">Throwable</span>) -> <span class="hljs-type">R</span> )</span></span>: R </pre></div><div id="7a52"><pre><span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-type"><T, R></span> Result<span class="hljs-type"><T></span>.<span class="hljs-title">getOrDefault</span><span class="hljs-params">(defaultValue: <span class="hljs-type">R</span>)</span></span>: R</pre></div><p id="0dbb">Returns the success value, or maps the exception to one/returns a default value:</p> <figure id="344d"> <div> <div> <img class="ratio" src="http://placehold.it/16x9"> <iframe class="" src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fpl.kotl.in%2FXSwWs7y5x&amp;display_name=Kotlin+Playground&amp;url=https%3A%2F%2Fpl.kotl.in%2FXSwWs7y5x&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=kotl" allowfullscreen="" frameborder="0" height="300" width="800"> </div> </div> </figure></iframe></div></div></figure><p id="af6e">Equivalent to <code>fold({ it }, ::onFailure)</code>/<code>fold({ it }, { defaultValue })</code></p><h1 id="b3e0">Mapping success Results</h1><h2 id="12e6">map()</h2><div id="ad72"><pre><span class="hljs-keyword">inline</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-type"><T, R></span> Result<span class="hljs-type"><T></span>.<span class="hljs-title">map</span><span class="hljs-params">( transform: (<span class="hljs-type">value</span>: <span class="hljs-type">T</span>) -> <span class="hljs-type">R</span> )</span></span>: Result<R></pre></div><p id="110e">Transforms a success value. Exceptions thrown inside <code>transform</code> get re-thrown.</p> <figure id="c054"> <div> <div> <img class="ratio" src="http://placehold.it/16x9"> <iframe class="" src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fpl.kotl.in%2FQcERm_QL3&amp;display_name=Kotlin+Playground&amp;url=https%3A%2F%2Fpl.kotl.in%2FQcERm_QL3&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=kotl" allowfullscreen="" frameborder="0" height="300" width="800"> </div> </div> </figure></iframe></div></div></figure><p id="661e">Equivalent to</p><div id="b9d3"><pre>fold({ Result.success(<span class="hljs-name">transform</span>(<span class="hljs-name">it</span>)) }, { Result.failure(<span class="hljs-name">it</span>) })</pre></div><h2 id="0a00">mapCatching()</h2><div id="85a4"><pre><span class="hljs-keyword">inline</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-type"><T, R></span> Result<span class="hljs-type"><T></span>.<span class="hljs-title">mapCatching</span><span class="hljs-params">( transform: (<span class="hljs-type">value</span>: <span class="hljs-type">T</span>) -> <span class="hljs-type">R</span> )</span></span>: Result<R></pre></div><p id="a097">Transforms a success value, converting any exception thrown in <code>transform</code> to a failure.</p> <figure id="a2dd"> <div> <div> <img class="ratio" src="http://placehold.it/16x9"> <iframe class="" src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fpl.kotl.in%2FZGTU-BjY4&amp;display_name=Kotlin+Playground&amp;url=https%3A%2F%2Fpl.kotl.in%2FZGTU-BjY4&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=kotl" allowfullscreen="" frameborder="0" height="300" width="800"> </div> </div> </figure></iframe></div></div></figure><p id="4b68">Equivalent to</p><div id="b572"><pre><span class="hljs-function"><span class="hljs-title">fold</span><span class="hljs-params">({ runCatching { transform(it)</span></span> } }, { Result<span class="hljs-selector-class">.failure</span>(it) })</pre></div><h2 id="883c">Which should you use?</h2><p id="a4b7">Only use <code>map</code>/<code>mapCatching</code> when transforming a <b>single</b> <code>Result</code>. We’ll talk about combining and composing multiple <code>Result</code>s in the <a href="https://readmedium.com/programming-with-result-combining-and-composing-result-2a56ea3a890c">next article</a>.</p><p id="ec66">Use <code>map</code> if the business/technical <i>essence</i> of the transformation <b>cannot cause</b> failure (e.g. multiplying a value by 2). Us

Options

e <code>mapCatching</code> if the essence of the transformation <b>can cause</b> failure (i.e. saving a record, performing a business calculation, etc).</p><p id="ae25">I’m emphasizing the <i>essence</i> of the transformation, because, in theory, every single line can throw an <code>OutOfMemory</code>, <code>ThreadDeath</code> etc. error. There’s really no point in wrapping every single line in a <code>runCatching</code> — these errors, if they really happen while doing something as trivial as multiplying by two, will get caught by one of the “upstream” callers of the method.</p><h1 id="9cbf">Mapping failure results</h1><h2 id="860f">recover()</h2><div id="4fc2"><pre><span class="hljs-keyword">inline</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-type"><T, R></span> Result<span class="hljs-type"><T></span>.<span class="hljs-title">recover</span><span class="hljs-params">( transform: (<span class="hljs-type">exception</span>: <span class="hljs-type">Throwable</span>) -> <span class="hljs-type">R</span> )</span></span>: Result<R></pre></div><p id="25b2">Transforms a failure value (<code>R</code> needs to be assignable to <code>T</code>). Similar to <code>map</code>, but operates on failures. Like <code>map</code>, exceptions thrown inside <code>transform</code> get re-thrown.</p> <figure id="5dd5"> <div> <div> <img class="ratio" src="http://placehold.it/16x9"> <iframe class="" src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fpl.kotl.in%2F-U4CWf9fG&amp;display_name=Kotlin+Playground&amp;url=https%3A%2F%2Fpl.kotl.in%2F-U4CWf9fG&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=kotl" allowfullscreen="" frameborder="0" height="300" width="800"> </div> </div> </figure></iframe></div></div></figure><p id="eb74">Equivalent to</p><div id="7771"><pre><span class="hljs-function"><span class="hljs-title">fold</span><span class="hljs-params">({ Result.success(it)</span></span> }, { Result<span class="hljs-selector-class">.success</span>(<span class="hljs-attribute">transform</span>(it)) })</pre></div><h2 id="235a">recoverCatching()</h2><div id="2205"><pre><span class="hljs-keyword">inline</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-type"><T, R></span> Result<span class="hljs-type"><T></span>.<span class="hljs-title">recoverCatching</span><span class="hljs-params">( transform: (<span class="hljs-type">exception</span>: <span class="hljs-type">Throwable</span>) -> <span class="hljs-type">R</span> )</span></span>: Result<R></pre></div><p id="e1c7">Transforms a failure value, converting any exception thrown in <code>transform</code> to a failure. Similar to <code>mapCatching</code>, but operates on failures.</p> <figure id="aed2"> <div> <div> <img class="ratio" src="http://placehold.it/16x9"> <iframe class="" src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fpl.kotl.in%2Fg8ZT_2fyK&amp;display_name=Kotlin+Playground&amp;url=https%3A%2F%2Fpl.kotl.in%2Fg8ZT_2fyK&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=kotl" allowfullscreen="" frameborder="0" height="300" width="800"> </div> </div> </figure></iframe></div></div></figure><h2 id="2157">Which should you use?</h2><p id="1165">As with <code>map</code>, use <code>recover</code> if the transformation is atomic and/or the business/technical essence of the transformation <b>doesn't include</b> failure. Use <code>recoverCatching</code> if the transformation is complex, and/or the essence of the transformation <b>includes</b> failure.</p><h1 id="86fd">Peeking</h1><h2 id="b9c5">onSuccess(), onFailure()</h2><div id="5f9c"><pre><span class="hljs-keyword">inline</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-type"><T></span> Result<span class="hljs-type"><T></span>.<span class="hljs-title">onSuccess</span><span class="hljs-params">( action: (<span class="hljs-type">value</span>: <span class="hljs-type">T</span>) -> <span class="hljs-type">Unit</span> )</span></span>: Result<T></pre></div><div id="b155"><pre><span class="hljs-keyword">inline</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-type"><T></span> Result<span class="hljs-type"><T></span>.<span class="hljs-title">onFailure</span><span class="hljs-params">( action: (<span class="hljs-type">exception</span>: <span class="hljs-type">Throwable</span>) -> <span class="hljs-type">Unit</span> )</span></span>: Result<T></pre></div><p id="e853">Executes action if <code>Result</code> is a success/failure. Returns the original <code>Result</code> unchanged. These functions are basically the equivalent of <code>also</code>, but in the context of <code>Result</code>. Their use-cases are the same.</p><p id="3c25">Go back to <a href="https://readmedium.com/programming-with-result-returning-a-result-33696cdce96f">Programming with Result: Returning a <code>Res</code>ult</a>, jump to the <a href="https://readmedium.com/table-of-contents-c52573cfa291">Table of Contents</a>, or continue to <a href="https://readmedium.com/programming-with-result-combining-and-composing-result-2a56ea3a890c">Programming with Result: Combining and Composing <code>Res</code>ults</a>.</p><figure id="8ecd"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*biBSB579iezsNvEQ_NMLBg.png"><figcaption></figcaption></figure></article></body>

Programming with Result: kotlin.Result

A short tour of the most important standard library functions for working with Result — general transformation using fold(), retrieving values using getOrThrow(), getOrElse()/getOrDefault(), mapping success using map()/mapCatching(), mapping failure using recover()/recoverCatching() and peeking using onSuccess()/onFailure().

— — — — — — — — — — — — — — —

THE CURRENT VERSION OF THIS ARTICLE IS PUBLISHED HERE.

— — — — — — — — — — — — — — —

Tags: #FUNDAMENTAL CONCEPT

This article is part of the Kotlin Primer, an opinionated guide to the Kotlin language, which is indented to help facilitate Kotlin adoption inside Java-centric organizations. It was originally written as an organizational learning resource for Etnetera a.s. and I would like to express my sincere gratitude for their support.

It is recommended to read the Introduction before moving on. Check out the Table of Contents for all articles.

The kotlin.Result type was added to the standard library to solve the issues we talked about in the previous articles, among others. Its implementation is a little different from the one we presented in the previous section — it is not a sealed class hierarchy, but instead implemented as a single value class.

Other than that, it is mostly the same as what we designed ourselves — it is still semantically equivalent to Result<T> = Success(T) | Failure, even though it is not implement that way.

To manually create a success or failure value, use the Result.success(value: T) and Result.failure(exception: Throwable) methods defined on the companion object. You can determine if the Result is a success or failure using the isSuccess and isFailure methods, and access the value/Throwable using getOrNull() and exceptionOrNull(). However, you will rarely need these, since they promote a more imperative style of programming, and should instead prefer one of the standard functions described bellow.

The standard library also defines a runCatching method, which is exactly the same as what we used before:

There is also a receiver version, T.runCatching. Basically, T.runCatching is to T.run what runCatching is to run:

Standard functions

All the standardized functions are specialized versions of the following function:

inline fun <T, R> Result<T>.fold(
    onSuccess: (value: T) -> R,
    onFailure: (exception: Throwable) -> R
): R

This transforms the value contained in the Result, depending on whether it is a success or failure. In essence, the function returns onSuccess(this.getOrNull()!!) if the Result is a success, and onFailure(this.exceptionOrNull()!!) otherwise.

Retrieving a value

getOrThrow()

fun <T> Result<T>.getOrThrow(): T

Returns the success value, or throws. While this might seem like a trivial function, it is actually incredibly useful when composing methods that return Results, and the subject is interesting enough that we'll dedicate a separate section to it bellow.

Equivalent to fold({ it }, { throw it }).

getOrElse(), getOrDefault()

inline fun <T, R> Result<T>.getOrElse(
    onFailure: (exception: Throwable) -> R
): R 
fun <T, R> Result<T>.getOrDefault(defaultValue: R): R

Returns the success value, or maps the exception to one/returns a default value:

Equivalent to fold({ it }, ::onFailure)/fold({ it }, { defaultValue })

Mapping success Results

map()

inline fun <T, R> Result<T>.map(
    transform: (value: T) -> R
): Result<R>

Transforms a success value. Exceptions thrown inside transform get re-thrown.

Equivalent to

fold({ Result.success(transform(it)) }, { Result.failure(it) })

mapCatching()

inline fun <T, R> Result<T>.mapCatching(
    transform: (value: T) -> R
): Result<R>

Transforms a success value, converting any exception thrown in transform to a failure.

Equivalent to

fold({ runCatching { transform(it) } }, { Result.failure(it) })

Which should you use?

Only use map/mapCatching when transforming a single Result. We’ll talk about combining and composing multiple Results in the next article.

Use map if the business/technical essence of the transformation cannot cause failure (e.g. multiplying a value by 2). Use mapCatching if the essence of the transformation can cause failure (i.e. saving a record, performing a business calculation, etc).

I’m emphasizing the essence of the transformation, because, in theory, every single line can throw an OutOfMemory, ThreadDeath etc. error. There’s really no point in wrapping every single line in a runCatching — these errors, if they really happen while doing something as trivial as multiplying by two, will get caught by one of the “upstream” callers of the method.

Mapping failure results

recover()

inline fun <T, R> Result<T>.recover(
    transform: (exception: Throwable) -> R
): Result<R>

Transforms a failure value (R needs to be assignable to T). Similar to map, but operates on failures. Like map, exceptions thrown inside transform get re-thrown.

Equivalent to

fold({ Result.success(it) }, { Result.success(transform(it)) })

recoverCatching()

inline fun <T, R> Result<T>.recoverCatching(
    transform: (exception: Throwable) -> R
): Result<R>

Transforms a failure value, converting any exception thrown in transform to a failure. Similar to mapCatching, but operates on failures.

Which should you use?

As with map, use recover if the transformation is atomic and/or the business/technical essence of the transformation doesn't include failure. Use recoverCatching if the transformation is complex, and/or the essence of the transformation includes failure.

Peeking

onSuccess(), onFailure()

inline fun <T> Result<T>.onSuccess(
    action: (value: T) -> Unit
): Result<T>
inline fun <T> Result<T>.onFailure(
    action: (exception: Throwable) -> Unit
): Result<T>

Executes action if Result is a success/failure. Returns the original Result unchanged. These functions are basically the equivalent of also, but in the context of Result. Their use-cases are the same.

Go back to Programming with Result: Returning a Result, jump to the Table of Contents, or continue to Programming with Result: Combining and Composing Results.

Java
Kotlin
Programming
Functional Programming
Exception Handling
Recommended from ReadMedium