# Introduction

A Java library to handle success and failure without exceptions

<picture><source srcset="/files/qAH4au64JJcmoUI67hP2" media="(prefers-color-scheme: dark)"><img src="/files/RxlJ4alKEGCsEqUsVBw4" alt=""></picture>

## Handle success and failure in Java without exceptions

Wave goodbye to slow exceptions and embrace clean, efficient error handling by encapsulating operations that may succeed or fail in a type-safe way.

<a href="/pages/4mPpfvbb7pgfQaPrChmN" class="button primary" data-icon="rocket-launch">Start here</a> <a href="https://github.com/LeakyAbstractions/result" class="button secondary" data-icon="github">Fork me on GitHub</a>

{% hint style="success" %}
Result is a Java library for modeling operation outcomes explicitly. It gives you a simpler, faster alternative to exception-driven flow when you want to represent both success and failure in a single, composable type.
{% endhint %}

### Why Result?

Optional is great for values that may be present or absent, but it does not explain **why** something is missing. Result fills that gap by carrying either a successful value or a failure reason, so your code can describe what happened instead of hiding it.

<div data-full-width="true"><picture><source srcset="/files/kWQeIb7485M6mhLjNl6d" media="(prefers-color-scheme: dark)"><img src="/files/8MFIsNfTwqUaeaWQk6Jm" alt="Mental Model"></picture></div>

### Quick Start

{% stepper %}
{% step %}
**Create a result from an operation**

```java
Result<User, Exception> result = Results.ofCallable(() -> db.getUser(id));
```

{% endstep %}

{% step %}
**Inspect whether it succeeded or failed**

```java
result.ifFailure(error -> logger.error("Couldn't get user: {}", id, error));
```

{% endstep %}

{% step %}
**Transform it if needed, then unwrap it as required**

```java
String name = result.mapSuccess(User::name).orElse("Anonymous");
```

{% endstep %}
{% endstepper %}

### Latest Releases

Available in [![Maven Central repository](/files/KZyuMTqJzr27sMsedQ09)](https://central.sonatype.com/artifact/com.leakyabstractions/result/)

<table data-card-size="large" data-view="cards" data-full-width="false"><thead><tr><th align="center"></th><th align="center"></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td align="center"><strong>Works with</strong></td><td align="center"><picture><source srcset="/files/AgjgdFMKFs6mtd07moPC" media="(prefers-color-scheme: dark)"><img src="/files/nwiWMp23AdTYlnSw9n4a" alt="Maven" data-size="original"></picture></td><td><a href="/pages/XgToMKoqME3I7phndKwE#maven">/pages/XgToMKoqME3I7phndKwE#maven</a></td></tr><tr><td align="center"><strong>Works with</strong></td><td align="center"><picture><source srcset="/files/qm9Kfbv3SKPBN6MQNOSP" media="(prefers-color-scheme: dark)"><img src="/files/xWJj1gpFfuDQ4sPJHh0u" alt="Gradle" data-size="original"></picture></td><td><a href="/pages/XgToMKoqME3I7phndKwE#gradle">/pages/XgToMKoqME3I7phndKwE#gradle</a></td></tr></tbody></table>

{% tabs %}
{% tab title="Maven" %}

```xml
<dependencies>
    <dependency>
        <groupId>com.leakyabstractions</groupId>
        <artifactId>result</artifactId>
        <version>1.0.0.0</version>
    </dependency>
</dependencies>
```

{% endtab %}

{% tab title="Gradle" %}

```groovy
dependencies {
    implementation("com.leakyabstractions:result:1.0.0.0")
}
```

{% endtab %}
{% endtabs %}

### Add-Ons

Integrate Result with popular libraries.

<table data-card-size="large" data-view="cards"><thead><tr><th align="center"></th><th align="center"></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td align="center"><strong>Assert results fluently with</strong></td><td align="center"><picture><source srcset="/files/mPGjqAswrx1gejSR1j7z" media="(prefers-color-scheme: dark)"><img src="/files/bpQVRtfP9WKEKO5pwgcR" alt="AssertJ" data-size="original"></picture></td><td><a href="/pages/qSR3nx6gmpph3cRO8O51">/pages/qSR3nx6gmpph3cRO8O51</a></td></tr><tr><td align="center"><strong>Serialize results to JSON with</strong></td><td align="center"><picture><source srcset="/files/BOkHI7rVUsQyopNckPes" media="(prefers-color-scheme: dark)"><img src="/files/7BfrAYOTIVm3sdyfc2sx" alt="Jackson" data-size="original"></picture></td><td><a href="/pages/piOZkyDIOXySq44ajtlT">/pages/piOZkyDIOXySq44ajtlT</a></td></tr></tbody></table>

### Demo Projects

Try it for yourself in 5 minutes.

<table data-card-size="large" data-view="cards"><thead><tr><th align="center"></th><th align="center"></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td align="center"><strong>Works with</strong></td><td align="center"><img src="/files/Rg7gUvcBAqbr6MWrGFOi" alt="Spring Boot" data-size="original"></td><td><a href="/pages/y7xsyH7hkafVbrIDUopX">/pages/y7xsyH7hkafVbrIDUopX</a></td></tr><tr><td align="center"><strong>Works with</strong></td><td align="center"><picture><source srcset="/files/sPsc7OitvZsiVeuAjmxw" media="(prefers-color-scheme: dark)"><img src="/files/JgEq5Hpq45nkp8JjCnfW" alt="Micronaut" data-size="original"></picture></td><td><a href="/pages/IBsmGrCHmTb5pYBP341k">/pages/IBsmGrCHmTb5pYBP341k</a></td></tr></tbody></table>

### Features

<table data-view="cards"><thead><tr><th align="center"></th><th align="center"></th><th align="center"></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td align="center"><picture><source srcset="/files/mxrhMGt0ZrXWTjyptyV5" media="(prefers-color-scheme: dark)"><img src="/files/z5ZQelqig25VNeWHkKUr" alt="Because exceptions are so last century."></picture></td><td align="center"><strong>Boost Performance</strong></td><td align="center">Avoid exception overhead and benefit from faster operations</td><td><a href="/pages/TCbqwyPa5tzunWSVkEGI">/pages/TCbqwyPa5tzunWSVkEGI</a></td></tr><tr><td align="center"><picture><source srcset="/files/Cj0ArLU9BOi6TbtxgH63" media="(prefers-color-scheme: dark)"><img src="/files/yR0KKvCbl5cncfRx14CE" alt="For a smooth ride from Optional to Result."></picture></td><td align="center"><strong>Simple API</strong></td><td align="center">Leverage a familiar interface for a smooth learning curve</td><td><a href="/pages/4mPpfvbb7pgfQaPrChmN">/pages/4mPpfvbb7pgfQaPrChmN</a></td></tr><tr><td align="center"><picture><source srcset="/files/w7tj8YofnXXEIDOYOti4" media="(prefers-color-scheme: dark)"><img src="/files/O1kvhR3xmuYuo7uir1XU" alt="Say goodbye to error-handling acrobatics."></picture></td><td align="center"><strong>Streamlined Error Handling</strong></td><td align="center">Handle failure explicitly to simplify error propagation</td><td><a href="/pages/LE6t8RMRScffoXjEI6ra">/pages/LE6t8RMRScffoXjEI6ra</a></td></tr><tr><td align="center"><picture><source srcset="/files/qFU7k4B4xf88HE2T76R6" media="(prefers-color-scheme: dark)"><img src="/files/2AP30kMHnghP8ROlL1AP" alt="Skip the exception rollercoaster and enjoy the smooth ride."></picture></td><td align="center"><strong>Safe Execution</strong></td><td align="center">Ensure safer and more predictable operation outcomes</td><td><a href="/pages/JNAiCBgXIxN292mjC4Da">/pages/JNAiCBgXIxN292mjC4Da</a></td></tr><tr><td align="center"><picture><source srcset="/files/0Fxb9G8zN1sxz1e1kldk" media="(prefers-color-scheme: dark)"><img src="/files/Go2oLHDfrSj7bQ82rzkZ" alt="So you can actually understand your own code next month."></picture></td><td align="center"><strong>Enhanced Readability</strong></td><td align="center">Reduce complexity to make your code easier to understand</td><td><a href="/pages/c5N5IxbAryKHA2EQVxz6">/pages/c5N5IxbAryKHA2EQVxz6</a></td></tr><tr><td align="center"><picture><source srcset="/files/jIHrb2NVRiqw7mGdGJFV" media="(prefers-color-scheme: dark)"><img src="/files/L9je3qQMUOYM7Upk9SxM" alt="For those who prefer elegance over chaos."></picture></td><td align="center"><strong>Functional Style</strong></td><td align="center">Embrace elegant, functional programming paradigms</td><td><a href="/pages/qwVsAsWtfvwhRkwzW4BV">/pages/qwVsAsWtfvwhRkwzW4BV</a></td></tr><tr><td align="center"><picture><source srcset="/files/fjD6l0CLPKQ4jA1tWMHB" media="(prefers-color-scheme: dark)"><img src="/files/25Ns7iQcjCDIVDewfkIy" alt="Because bloated libraries are so overrated."></picture></td><td align="center"><strong>Lightweight</strong></td><td align="center">Keep your project slim with no extra dependencies</td><td><a href="/pages/XgToMKoqME3I7phndKwE">/pages/XgToMKoqME3I7phndKwE</a></td></tr><tr><td align="center"><picture><source srcset="/files/bGe40FR0CD5zcfXAtP4c" media="(prefers-color-scheme: dark)"><img src="/files/ZaqRI9nCTcvOb3W9OM9P" alt="Feel free to tweak and share — no strings attached."></picture></td><td align="center"><strong>Open Source</strong></td><td align="center">Enjoy transparent, permissive Apache 2 licensing</td><td><a href="/pages/Nlloko09FaI70E1kvKT5">/pages/Nlloko09FaI70E1kvKT5</a></td></tr><tr><td align="center"><picture><source srcset="/files/g5vJrJmNj8wURQOUVecr" media="(prefers-color-scheme: dark)"><img src="/files/3Q7JIYcE2Y6cZo1CMXrb" alt="Whether you&#x27;re stuck in the past or embracing the future, we&#x27;ve got you covered."></picture></td><td align="center"><strong>Pure Java</strong></td><td align="center">Seamless compatibility from JDK8 to the latest versions</td><td><a href="https://github.com/LeakyAbstractions/result/">https://github.com/LeakyAbstractions/result/</a></td></tr></tbody></table>

### Ready to Tap into the Power of Results?

Read the guide and transform your error handling today.

{% content-ref url="/pages/4mPpfvbb7pgfQaPrChmN" %}
[Getting Started](/docs/start)
{% endcontent-ref %}

{% content-ref url="/pages/NF0v4IGYyNzpoWOFrbeh" %}
[Basic Usage](/docs/basic)
{% endcontent-ref %}

{% content-ref url="/pages/9e1kunsGc7QFZHqrzzLE" %}
[Advanced Usage](/docs/advanced)
{% endcontent-ref %}

Also available as an **ebook** in multiple formats. [Download your free copy now!](https://leanpub.com/result/)

### TL;DR

Not a fan of reading long docs? No worries! Tune in to *Deep Dive*, a podcast generated by [NetbookLM](https://notebooklm.google.com/). In just a few minutes, you'll get the essential details and a fun intro to what this library can do for you!

{% embed url="<https://www.youtube.com/watch?v=sTBRnm0KosM>" %}


# Getting Started

How to get up and running with Results in no time

{% hint style="success" %}
The best way to think of Results is as a super-powered version of Java's Optionals.
{% endhint %}

`Result` builds upon the familiar concept of `Optional`, enhancing it with the ability to represent both success and failure states.

![No need to return null or throw an exception: just return a failed result.](/files/9Ac5JTkazU5Yk2OAZp6u)

{% tabs %}
{% tab title="Why Results over Optionals?" %}
`Optional` class is useful for representing values that might be present or absent, eliminating the need for null checks. However, Optionals fall short when it comes to error handling because they do not convey why a value is lacking. `Result` addresses this limitation by encapsulating both successful values and failure reasons, offering a more expressive way to reason about what went wrong.
{% endtab %}

{% tab title="Result API" %}
Results provide the same methods as Optionals, plus additional ones to handle failure states effectively.

| [`Optional`](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/Optional.html)                                                                        | [`Result`](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html)                                                                                 |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [isPresent](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/Optional.html#isPresent\(\))                                                           | [hasSuccess](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#hasSuccess--)                                                                  |
| [isEmpty](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/Optional.html#isEmpty\(\))                                                               | [hasFailure](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#hasFailure--)                                                                  |
| [get](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/Optional.html#get\(\))                                                                       | [getSuccess](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#getSuccess--)                                                                  |
|                                                                                                                                                                           | [getFailure](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#getFailure--)                                                                  |
| [orElse](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/Optional.html#orElse\(java.lang.Object\))                                                 | [orElse](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#orElse-S-)                                                                         |
| [orElseGet](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/Optional.html#orElseGet\(java.util.function.Supplier\))                                | [orElseMap](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#orElseMap-java.util.function.Function-)                                         |
| [stream](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/Optional.html#stream\(\))                                                                 | [streamSuccess](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#streamSuccess--)                                                            |
|                                                                                                                                                                           | [streamFailure](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#streamFailure--)                                                            |
| [ifPresent](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/Optional.html#ifPresent\(java.util.function.Consumer\))                                | [ifSuccess](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#ifSuccess-java.util.function.Consumer-)                                         |
|                                                                                                                                                                           | [ifFailure](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#ifFailure-java.util.function.Consumer-)                                         |
| [ifPresentOrElse](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/Optional.html#ifPresentOrElse\(java.util.function.Consumer,java.lang.Runnable\)) | [ifSuccessOrElse](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#ifSuccessOrElse-java.util.function.Consumer-java.util.function.Consumer-) |
| [filter](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/Optional.html#filter\(java.util.function.Predicate\))                                     | [filter](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#filter-java.util.function.Predicate-java.util.function.Function-)                  |
|                                                                                                                                                                           | [recover](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#recover-java.util.function.Predicate-java.util.function.Function-)                |
| [map](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/Optional.html#map\(java.util.function.Function\))                                            | [mapSuccess](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#mapSuccess-java.util.function.Function-)                                       |
|                                                                                                                                                                           | [mapFailure](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#mapFailure-java.util.function.Function-)                                       |
|                                                                                                                                                                           | [map](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#map-java.util.function.Function-java.util.function.Function-)                         |
| [flatMap](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/Optional.html#flatMap\(java.util.function.Function\))                                    | [flatMapSuccess](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#flatMapSuccess-java.util.function.Function-)                               |
| [or](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/Optional.html#or\(java.util.function.Supplier\))                                              | [flatMapFailure](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#flatMapFailure-java.util.function.Function-)                               |
|                                                                                                                                                                           | [flatMap](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#flatMap-java.util.function.Function-java.util.function.Function-)                 |
| {% endtab %}                                                                                                                                                              |                                                                                                                                                                                                         |
| {% endtabs %}                                                                                                                                                             |                                                                                                                                                                                                         |

By leveraging Results, you can unleash a powerful tool for error handling that goes beyond the capabilities of traditional Optionals, leading to more robust and maintainable Java code.

## Results in a Nutshell

In Java, methods that can fail typically do so by throwing exceptions. Then, exception-throwing methods are called from inside a `try` block to handle errors in a separate `catch` block.

![Using Exceptions](/files/MtsCgLmcDB1meZgLbrBg)

This approach is lengthy, and that's not the only problem — it's also very slow.

{% hint style="info" %}
Conventional wisdom says **exceptional logic shouldn't be used for normal program flow**. Results make us deal with expected error situations explicitly to enforce good practices and make our programs [run faster](/extra/benchmarks).
{% endhint %}

Let's now look at how the above code could be refactored if `connect()` returned a `Result` object instead of throwing an exception.

![Using Results](/files/ue0eK3dU4ZqFCzupPkPY)

In the example above, we used only 4 lines of code to replace the 10 that worked for the first one. But we can effortlessly make it shorter by chaining methods. In fact, since we were returning `-1` just to signal that the underlying operation failed, we are better off returning a `Result` object upstream. This will allow us to compose operations on top of `getServerUptime()` just like we did with `connect()`.

![Embracing Results](/files/sqUQU1NtcP9qAGxNxn1Y)

{% hint style="success" %}
`Result` objects are immutable, providing thread safety without the need for synchronization. This makes them ideal for multi-threaded applications, ensuring predictability and eliminating side effects.
{% endhint %}


# Adding Result to Your Build

How to add Result as a dependency to your build

This library adheres to [Pragmatic Versioning](https://pragver.github.io/) to communicate the backwards compatibility of each version.

The latest releases are available in [![Maven Central repository](/files/KZyuMTqJzr27sMsedQ09)](https://central.sonatype.com/artifact/com.leakyabstractions/result/)

Result supports both [**Maven**](https://maven.apache.org/) and [**Gradle**](https://gradle.org/) for seamless integration into your Java build workflow.

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th data-hidden data-card-target data-type="content-ref"></th><th data-hidden data-card-cover data-type="image">Cover image</th><th data-hidden data-card-cover-dark data-type="image">Cover image (dark)</th></tr></thead><tbody><tr><td><a href="https://maven.apache.org/"><strong>Apache Maven</strong></a> is a convention-based Java build tool that uses XML configuration to manage dependencies, compile code, and package applications in a standardized lifecycle.</td><td><a href="#maven">#maven</a></td><td data-object-fit="contain"><a href="/files/nwiWMp23AdTYlnSw9n4a">/files/nwiWMp23AdTYlnSw9n4a</a></td><td><a href="/files/AgjgdFMKFs6mtd07moPC">/files/AgjgdFMKFs6mtd07moPC</a></td></tr><tr><td><a href="https://gradle.org/"><strong>Gradle</strong></a> is a flexible and high-performance build tool that uses a Groovy or Kotlin DSL to define builds, offering advanced customization and fast incremental builds.</td><td><a href="#gradle">#gradle</a></td><td data-object-fit="contain"><a href="/files/xWJj1gpFfuDQ4sPJHh0u">/files/xWJj1gpFfuDQ4sPJHh0u</a></td><td><a href="/files/qm9Kfbv3SKPBN6MQNOSP">/files/qm9Kfbv3SKPBN6MQNOSP</a></td></tr></tbody></table>

## Artifact Coordinates

Add this Maven dependency to your build:

| Group ID                | Artifact ID | Latest Version                                                                                |
| ----------------------- | ----------- | --------------------------------------------------------------------------------------------- |
| `com.leakyabstractions` | `result`    | ![](https://img.shields.io/endpoint?url=https://dev.leakyabstractions.com/result/latest.json) |

{% hint style="success" %}
[Maven Central](https://central.sonatype.com/artifact/com.leakyabstractions/result/) provides snippets for different build tools to declare this dependency.
{% endhint %}

## Maven

Add Result as a Maven dependency to your project.

```xml
<dependencies>
    <dependency>
        <groupId>com.leakyabstractions</groupId>
        <artifactId>result</artifactId>
        <version>1.0.0.0</version>
    </dependency>
</dependencies>
```

## Gradle

Add Result as a Gradle dependency to your project.

```groovy
dependencies {
    implementation("com.leakyabstractions:result:1.0.0.0")
}
```

{% hint style="info" %}
This is the most common configuration for projects using Result internally. If we were building a library that exposed Result in its public API, [we should use `api` instead of `implementation`](https://docs.gradle.org/current/userguide/java_library_plugin.html#sec:java_library_separation).
{% endhint %}

## Conclusion

We learned how to add the library to your project using either Maven or Gradle. By including the correct dependencies, you're now ready to start leveraging the power of Results in your applications.


# Creating Results

How to instantiate new Result objects

There are several ways to create result objects.

## Successful Results

A successful result contains a non-null value produced by an operation when everything works as intended. We can use [`Results::success`](https://javadoc.io/doc/com.leakyabstractions/result/latest/com/leakyabstractions/result/core/Results.html#success-S-) to create a new instance.

```java
@Test
void testSuccess() {
  // When
  Result<Integer, ?> result = Results.success(200);
  // Then
  assertTrue(result::hasSuccess);
  assertFalse(result::hasFailure);
}
```

{% hint style="info" %}
Note that we can invoke [`Result::hasSuccess`](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#hasSuccess--) or [`Result::hasFailure`](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#hasFailure--) to check whether a result is successful or failed (more on this in the [next section](/docs/basic/checking)).
{% endhint %}

## Failed Results

On the other hand, a failed result holds a value representing the problem that prevented the operation from completing. We can use [`Results::failure`](https://javadoc.io/doc/com.leakyabstractions/result/latest/com/leakyabstractions/result/core/Results.html#failure-F-) to create a new one.

```java
@Test
void testFailure() {
  // When
  Result<?, String> result = Results.failure("The operation failed");
  // Then
  assertTrue(result::hasFailure);
  assertFalse(result::hasSuccess);
}
```

{% hint style="danger" %}
Failure values cannot be `null` either.
{% endhint %}

## Results Based on Nullable Values

When we need to create results that depend on a possibly null value, we can use [`Results::ofNullable`](https://javadoc.io/doc/com.leakyabstractions/result/latest/com/leakyabstractions/result/core/Results.html#ofNullable-S-F-). If the first argument is `null`, then the second one will be used to create a failed result.

```java
@Test
void testOfNullable() {
  // Given
  String string1 = "The operation succeeded";
  String string2 = null;
  // When
  Result<String, Integer> result1 = Results.ofNullable(string1, 404);
  Result<String, Integer> result2 = Results.ofNullable(string2, 404);
  // Then
  assertTrue(result1::hasSuccess);
  assertTrue(result2::hasFailure);
}
```

{% hint style="info" %}
The second argument can be either a failure value or a function that produces a failure value.
{% endhint %}

## Results Based on Optionals

We can also use [`Results::ofOptional`](https://javadoc.io/doc/com.leakyabstractions/result/latest/com/leakyabstractions/result/core/Results.html#ofOptional-java.util.Optional-F-) to create results that depend on an [`Optional`](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/Optional.html) value. If the first argument is an empty optional, then the second one will be used to create a failed result.

```java
@Test
void testOfOptional() {
  // Given
  Optional<BigDecimal> optional1 = Optional.of(BigDecimal.ONE);
  Optional<BigDecimal> optional2 = Optional.empty();
  // When
  Result<BigDecimal, Integer> result1 = Results.ofOptional(optional1, -1);
  Result<BigDecimal, Integer> result2 = Results.ofOptional(optional2, -1);
  // Then
  assertTrue(result1::hasSuccess);
  assertTrue(result2::hasFailure);
}
```

{% hint style="info" %}
The second argument can be a [`Supplier`](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/function/Supplier.html) too.
{% endhint %}

## Results Based on Callables

Finally, if we have a task that may either return a success value or throw an exception, we can encapsulate it as a result using [`Results::ofCallable`](https://javadoc.io/doc/com.leakyabstractions/result/latest/com/leakyabstractions/result/core/Results.html#ofCallable-java.util.concurrent.Callable-) so we don't need to use a *try-catch* block.

```java
String task1() {
  return "OK";
}

String task2() throws Exception {
  throw new Exception("Whoops!");
}

@Test
void testOfCallable() {
  // When
  Result<String, Exception> result1 = Results.ofCallable(this::task1);
  Result<String, Exception> result2 = Results.ofCallable(this::task2);
  // Then
  assertTrue(result1::hasSuccess);
  assertTrue(result2::hasFailure);
}
```

{% hint style="success" %}
This method enables compatibility with legacy or third-party code that uses exceptions to indicate operation failure.
{% endhint %}

## Conclusion

We've covered how to create new instances of `Result` using various factory methods provided by the `Results` class. Each method serves a specific purpose, allowing you to select the most suitable one based on the situation.


# Basic Usage

How to solve simple use-case scenarios

In this section, we'll cover foundational use cases, including checking the status of a result, unwrapping the value inside a result, and taking different actions based on success or failure.

![No need for if blocks or early return statements when you can handle success and failure without any hassle.](/files/gDQIVaJ2cuXyvLaG9jnE)

These basics will help you handle errors more cleanly and efficiently without cluttering your code with *try-catch* blocks.


# Checking Success or Failure

How to find out if the operation succeded or failed

As we discovered earlier, we can easily determine if a given `Result` instance is successful or not.

## Checking Success

We can use [`Result::hasSuccess`](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#hasSuccess--) to obtain a `boolean` value that represents whether a result is successful.

```java
@Test
void testHasSuccess() {
  // Given
  Result<?, ?> result1 = success(1024);
  Result<?, ?> result2 = failure(1024);
  // When
  boolean result1HasSuccess = result1.hasSuccess();
  boolean result2HasSuccess = result2.hasSuccess();
  // Then
  assertTrue(result1HasSuccess);
  assertFalse(result2HasSuccess);
}
```

## Checking Failure

We can also use [`Result::hasFailure`](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#hasFailure--) to find out if a result contains a failure value.

```java
@Test
void testHasFailure() {
  // Given
  Result<?, ?> result1 = success(512);
  Result<?, ?> result2 = failure(512);
  // When
  boolean result1HasFailure = result1.hasFailure();
  boolean result2HasFailure = result2.hasFailure();
  // Then
  assertFalse(result1HasFailure);
  assertTrue(result2HasFailure);
}
```

## Conclusion

We discussed how to determine the state of a Result object using [`hasSuccess`](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#hasSuccess--) and [`hasFailure`](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#hasFailure--). These methods provide a straightforward way to identify the outcome of an operation, helping you make decisions based on the outcome.


# Unwrapping Values

How to get values out of Result objects

In essence, a `Result` object is just a container that wraps a success or a failure value for us. Therefore, sometimes you are going to want to get that value out of the container.

{% hint style="info" %}
As useful as this may seem, we will soon realize that we won't be doing it very often.
{% endhint %}

## Unwrapping Success

The most basic way to retrieve the success value wrapped inside a result is by using [`Result::getSuccess`](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#getSuccess--). This method will return an optional success value, depending on whether the result was actually successful or not.

```java
@Test
void testGetSuccess() {
  // Given
  Result<?, ?> result1 = success("SUCCESS");
  Result<?, ?> result2 = failure("FAILURE");
  // Then
  Optional<?> success1 = result1.getSuccess();
  Optional<?> success2 = result2.getSuccess();
  // Then
  assertEquals("SUCCESS", success1.get());
  assertTrue(success2::isEmpty);
}
```

## Unwrapping Failure

Similarly, we can use [`Result::getFailure`](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#getFailure--) to obtain the failure value held by a `Result` object.

```java
@Test
void testGetFailure() {
  // Given
  Result<?, ?> result1 = success("SUCCESS");
  Result<?, ?> result2 = failure("FAILURE");
  // Then
  Optional<?> failure1 = result1.getFailure();
  Optional<?> failure2 = result2.getFailure();
  // Then
  assertTrue(failure1::isEmpty);
  assertEquals("FAILURE", failure2.get());
}
```

{% hint style="success" %}
Unlike [`Optional::get`](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/Optional.html#get\(\)), these methods are null-safe. However, in practice, we will not be using them frequently. Especially, since there are more convenient ways to get the success value out of a result.
{% endhint %}

## Using Alternative Success

We can use [`Result::orElse`](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#orElse-S-) to provide an alternative success value that must be returned when the result is unsuccessful.

```java
@Test
void testGetOrElse() {
  // Given
  Result<String, String> result1 = success("IDEAL");
  Result<String, String> result2 = failure("ERROR");
  String alternative = "OTHER";
  // When
  String value1 = result1.orElse(alternative);
  String value2 = result2.orElse(alternative);
  // Then
  assertEquals("IDEAL", value1);
  assertEquals("OTHER", value2);
}
```

{% hint style="info" %}
Note that alternative success values can be `null`.
{% endhint %}

## Mapping Failure

The [`Result::orElseMap`](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#orElseMap-java.util.function.Function-) method is similar to [`Optional::orElseGet`](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/Optional.html#orElseGet\(java.util.function.Supplier\)), but it takes a mapping [`Function`](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/function/Function.html) instead of a [`Supplier`](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/function/Supplier.html). The function will receive the failure value to produce the alternative success value.

```java
@Test
void testGetOrElseMap() {
  // Given
  Result<String, Integer> result1 = success("OK");
  Result<String, Integer> result2 = failure(1024);
  Result<String, Integer> result3 = failure(-256);
  Function<Integer, String> mapper = x -> x > 0 ? "HI" : "LO";
  // When
  String value1 = result1.orElseMap(mapper);
  String value2 = result2.orElseMap(mapper);
  String value3 = result3.orElseMap(mapper);
  // Then
  assertEquals("OK", value1);
  assertEquals("HI", value2);
  assertEquals("LO", value3);
}
```

{% hint style="info" %}
Although probably not the best practice, the mapping function may return `null`.
{% endhint %}

## Streaming Success or Failure

Finally, we can use [`Result::streamSuccess`](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#streamSuccess--) and [`Result::streamFailure`](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#streamFailure--) to wrap the value held by an instance of `Result` into a possibly-empty [`Stream`](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/stream/Stream.html) object.

```java
@Test
void testStreamSuccess() {
  // Given
  Result<?, ?> result1 = success("Yes");
  Result<?, ?> result2 = failure("No");
  // When
  Stream<?> stream1 = result1.streamSuccess();
  Stream<?> stream2 = result2.streamSuccess();
  // Then
  assertEquals("Yes", stream1.findFirst().orElse(null));
  assertNull(stream2.findFirst().orElse(null));
}

@Test
void testStreamFailure() {
  // Given
  Result<?, ?> result1 = success("Yes");
  Result<?, ?> result2 = failure("No");
  // When
  Stream<?> stream1 = result1.streamFailure();
  Stream<?> stream2 = result2.streamFailure();
  // Then
  assertNull(stream1.findFirst().orElse(null));
  assertEquals("No", stream2.findFirst().orElse(null));
}
```

## Conclusion

We explored various ways to retrieve values from results. Using these methods you can efficiently access the underlying data within a Result object, whether it's a success or a failure.


# Conditional Actions

How to handle success and failure scenarios

We'll now delve into a set of methods that allow you to take conditional actions based on the state of a result. They provide a cleaner and more expressive way to handle success and failure scenarios, eliminating the need for lengthy *if/else* blocks.

## Handling Success

We can use [`Result::ifSuccess`](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#ifSuccess-java.util.function.Consumer-) to specify an action that must be executed if the result represents a successful outcome. This method takes a [consumer function](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/function/Consumer.html) that will be applied to the success value wrapped by the result.

```java
@Test
void testIfSuccess() {
  // Given
  List<Object> list = new ArrayList<>();
  Result<Integer, String> result = success(100);
  // When
  result.ifSuccess(list::add);
  // Then
  assertEquals(100, list.getFirst());
}
```

In this example, `ifSuccess` ensures that the provided action (adding the success value to the list) is only executed if the parsing operation is successful.

## Handling Failure

On the other hand, we can use [`Result::ifFailure`](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#ifFailure-java.util.function.Consumer-) method to define an action that must be taken when the result represents a failure. This method also takes a [`Consumer`](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/function/Consumer.html) that will be applied to the failure value inside the result.

```java
@Test
void testIfFailure() {
  // Given
  List<Object> list = new ArrayList<>();
  Result<Integer, String> result = failure("ERROR");
  // When
  result.ifFailure(list::add);
  // Then
  assertEquals("ERROR", list.getFirst());
}
```

Here, `ifFailure` ensures that the provided action (adding the failure value to the list) is only executed if the parsing operation fails.

## Handling Both Scenarios

Finally, [`Result::ifSuccessOrElse`](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#ifSuccessOrElse-java.util.function.Consumer-java.util.function.Consumer-) allows you to specify two separate actions: one for when the operation succeeded and another for when it failed. This method takes two [consumer functions](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/function/Consumer.html): the first for handling the success case and the second for handling the failure case.

```java
@Test
void testIfSuccessOrElse() {
  // Given
  List<Object> list1 = new ArrayList<>();
  List<Object> list2 = new ArrayList<>();
  Result<Long, String> result1 = success(100L);
  Result<Long, String> result2 = failure("ERROR");
  // When
  result1.ifSuccessOrElse(list1::add, list1::add);
  result2.ifSuccessOrElse(list2::add, list2::add);
  // Then
  assertEquals(100L, list1.getFirst());
  assertEquals("ERROR", list2.getFirst());
}
```

In this example, `ifSuccessOrElse` simplifies conditional logic by providing a single method to handle both success and failure scenarios, making the code more concise and readable.

## Conclusion

We explained how to handle success and failure scenarios using these three methods. They provide a powerful way to perform conditional actions based on the state of a Result, streamlining your error handling and making your code more readable and maintainable.


# Advanced Usage

How to take Result objects to the next level

While understanding the basics provides a solid foundation, the true potential of result objects is unlocked through their functional capabilities. Mastering these techniques enables concise and readable error handling by leveraging the power of [monadic composition](https://en.wikipedia.org/wiki/Monad_\(functional_programming\)).

{% hint style="success" %}
The most idiomatic approach to handling results involves screening them and applying various mapping and flat-mapping methods to transform and compose behavior.
{% endhint %}

![Results can be filtered and transformed just like Java streams.](/files/7kgaiSKuSHAcJ681aLOM)

This section will guide you through these powerful tools, demonstrating how to manipulate results effectively so you can craft more robust and maintainable Java applications.


# Screening Results

How to reject success values and accept failure values

{% hint style="info" %}
Screening mechanisms provide greater flexibility in handling edge cases and enable more robust error recovery strategies.
{% endhint %}

The following methods allow you to run inline tests on the wrapped value of a result to dynamically transform a success into a failure or a failure into a success.

## Validating Success

The [`Result::filter`](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#filter-java.util.function.Predicate-java.util.function.Function-) method allows you to transform a success into a failure based on certain conditions. It takes two parameters:

1. A [`Predicate`](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/function/Predicate.html) to determine if the success value is acceptable.
2. A mapping [`Function`](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/function/Function.html) that will produce a failure value if the value is deemed unacceptable.

{% hint style="success" %}
This can be used to enforce additional validation constraints on success values.
{% endhint %}

```java
@Test
void testFilter() {
  // Given
  Result<Integer, String> result = success(1);
  // When
  Result<Integer, String> filtered = result.filter(x -> x % 2 == 0, x -> "It's odd");
  // Then
  assertTrue(filtered.hasFailure());
}
```

In this example, we use a lambda expression to validate that the success value inside `result` is even. Since the number is odd, it transforms the result into a failure.

{% hint style="danger" %}
Note that it is illegal for the mapping function to return `null`.
{% endhint %}

## Recovering From Failure

The [`Result::recover`](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#recover-java.util.function.Predicate-java.util.function.Function-) method allows you to transform a failure into a success based on certain conditions. It also receives two parameters:

1. A [`Predicate`](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/function/Predicate.html) to determine if the failure value is recoverable.
2. A mapping [`Function`](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/function/Function.html) that will produce a success value from the acceptable failure value.

{% hint style="success" %}
This method is useful for implementing fallback mechanisms or recovery strategies, ensuring the application logic remains resilient and adaptable.
{% endhint %}

```java
@Test
void testRecover() {
  // Given
  Result<Integer, String> result = failure("OK");
  // When
  Result<Integer, String> filtered = result.recover("OK"::equals, String::length);
  // Then
  assertTrue(filtered.hasSuccess());
}
```

In this example, we use method references to check if the failure value equals `OK` and then transform the result into a success.

## Conclusion

We covered how to filter out unwanted success values and accept failure values using [`filter`](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#filter-java.util.function.Predicate-java.util.function.Function-) and [`recover`](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#recover-java.util.function.Predicate-java.util.function.Function-). These methods enable you to refine results based on specific criteria, ensuring that only the relevant values are processed down the line.


# Transforming Results

How to transform values wrapped inside Results

Transforming result objects is a key feature that enables you to compose complex operations in a clean and functional style. There are two primary techniques used for these transformations.

## Mapping Results

Mapping involves applying a function to the value inside a result to produce a new result object.

### Mapping Success Values

We can use [`Result::mapSuccess`](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#mapSuccess-java.util.function.Function-) to apply a function to the success value of a result, transforming it into a new success value. If the result is a failure, it remains unchanged.

```java
@Test
void testMapSuccess() {
  // Given
  Result<String, ?> result = success("HELLO");
  // When
  Result<Integer, ?> mapped = result.mapSuccess(String::length);
  // Then
  assertEquals(5, mapped.orElse(null));
}
```

In this example, we wrap a `String` inside a `Result` object and invoke `mapSuccess` to calculate its length and wrap it inside a new `Result` object.

### Mapping Failure Values

Next up, we can use [`Result::mapFailure`](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#mapFailure-java.util.function.Function-) to apply a function to the failure value, transforming it into a new one. If the result is a success, it remains unchanged.

```java
@Test
void testMapFailure() {
  // Given
  Result<?, BigDecimal> result = failure(ONE);
  // When
  Result<?, Boolean> mapped = result.mapFailure(TWO::equals);
  // Then
  assertFalse(mapped.getFailure().orElse(null));
}
```

Here, we invoke `mapFailure` to transform the failure type of the result from `String` to `Boolean` for demonstration purposes.

### Mapping Both Success and Failure

The [`Result::map`](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#map-java.util.function.Function-java.util.function.Function-) method simultaneously handles both success and failure cases by applying two separate functions: one for transforming the success value and one for transforming the failure value.

```java
@Test
void testMap() {
  // Given
  Result<String, BigDecimal> result1 = success("HELLO");
  Result<String, BigDecimal> result2 = failure(ONE);
  // When
  Result<Integer, Boolean> mapped1 = result1.map(String::length, TWO::equals);
  Result<Integer, Boolean> mapped2 = result2.map(String::length, TWO::equals);
  // Then
  assertEquals(5, mapped1.orElse(null));
  assertFalse(mapped2.getFailure().orElse(null));
}
```

## Flat-Mapping Results

Flat-mapping is used to chain operations that return results themselves, flattening the nested structures into a single result object. This allows you to transform a success into a failure, or a failure into a success.

To illustrate flat-mapping concepts, the next examples will follow a familiar "pet store" theme. This involves three Java types: `Pet`, `PetError`, and `PetStore`. These types will help us demonstrate the effective use of flat-mapping methods.

```java
enum PetError {NOT_FOUND, NO_CONFIG}

record Pet(long id, String name) {

  static final Pet DEFAULT = new Pet(0, "Default pet");
  static final Pet ROCKY = new Pet(1, "Rocky");
  static final Pet GARFIELD = new Pet(2, "Garfield");
}

record PetStore(Pet... pets) {

  PetStore() {
    this(Pet.ROCKY, Pet.GARFIELD);
  }

  Result<Pet, PetError> find(long id) {
    Optional<Pet> found = stream(pets).filter(pet -> pet.id() == id).findAny();
    return Results.ofOptional(found, NOT_FOUND);
  }

  Result<Pet, PetError> getDefaultPet(PetError error) {
    return error == NO_CONFIG ? success(Pet.DEFAULT) : failure(error);
  }

  Result<Long, PetError> getDefaultPetId(PetError error) {
    return getDefaultPet(error).mapSuccess(Pet::id);
  }
}
```

With these types defined, we'll explore how to use various flat-mapping methods to transform result objects and manage pet-related operations in our imaginary pet store.

### Flat-Mapping Successful Results

Use [`Result::flatMapSuccess`](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#flatMapSuccess-java.util.function.Function-) to chain an operation that returns a result object. This method applies a mapping function to the success value, replacing the original result with the new one returned by the function. If the result is a failure, it remains unchanged.

```java
@Test
void testFlatMapSuccess() {
  // Given
  PetStore store = new PetStore();
  Result<Long, PetError> result = success(100L);
  // When
  Result<Pet, PetError> mapped = result.flatMapSuccess(store::find);
  // Then
  assertEquals(NOT_FOUND, mapped.getFailure().orElse(null));
}
```

This example starts with a successful result containing a wrong pet ID (not found in the pet store). When we flat-map it with the store's `find` method reference, the final result contains a pet error.

### Flat-Mapping Failed Results

Use [`Result::flatMapFailure`](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#flatMapFailure-java.util.function.Function-) to chain a result-bearing operation. This method also replaces the original result with the new one returned by the mapping function. If the result is a success, it remains unchanged.

```java
@Test
void testFlatMapFailure() {
  // Given
  PetStore store = new PetStore();
  Result<Long, PetError> result = failure(NO_CONFIG);
  // When
  Result<Long, PetError> mapped = result.flatMapFailure(store::getDefaultPetId);
  // Then
  assertEquals(Pet.DEFAULT.id(), mapped.orElse(null));
}
```

Here we start with a failed result containing a pet error. When we flat-map it with the store's `getDefaultPetId` method reference, the final result contains the ID of the default pet in the store.

### Flat-Mapping Both Success and Failure

The [`Result::flatMap`](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#flatMap-java.util.function.Function-java.util.function.Function-) method handles both success and failure cases by applying the appropriate function based on the status of the original result.

```java
@Test
void testFlatMap() {
  // Given
  PetStore store = new PetStore();
  Result<Long, PetError> result1 = success(100L);
  Result<Long, PetError> result2 = failure(NO_CONFIG);
  // When
  Result<Pet, PetError> mapped1 = result1.flatMap(store::find, store::getDefaultPet);
  Result<Pet, PetError> mapped2 = result2.flatMap(store::find, store::getDefaultPet);
  // Then
  assertEquals(NOT_FOUND, mapped1.getFailure().orElse(null));
  assertEquals(Pet.DEFAULT, mapped2.orElse(null));
}
```

This example starts with a successful result containing a wrong pet ID (not found in the pet store). When we flat-map it with the store's `find` method reference, the final result contains a pet error.

Here we start with a failed result containing a pet error. When we flat-map it with the store's `getDefaultPetId` method reference, the final result contains the ID of the default pet in the store.

## Conclusion

We demonstrated how to transform results in a concise and functional manner, enhancing the clarity and flexibility of your error-handling and data-processing logic.


# Recap

Level up and lessons learned

Congratulations on reaching the end of this guide! By now, you should have a solid understanding of how to use results in your Java applications effectively. Here's a brief recap of what you've learned:

* **Getting Started:** You learned how to integrate result objects into your codebase and instantiate new ones.
* **Basic Usage:** You explored foundational operations like checking statuses, unwrapping values, and executing conditional actions based on result status, enabling you to respond dynamically to success and failure scenarios.
* **Advanced Usage:** You delved into more sophisticated techniques like screening results to transform successes and failures based on conditions, and leveraging mapping and flat-mapping methods to compose behaviors in a functional style.

For more details on the Result API, you can read the [Javadoc reference documentation](https://javadoc.io/doc/com.leakyabstractions/result-api/).

{% hint style="success" %}
The full source code for the examples is [available on GitHub](https://github.com/LeakyAbstractions/result-docs/tree/main/example/src/test/java/com/example).
{% endhint %}

Next, we'll introduce additional resources where you can further enhance your understanding and skills. Let's continue expanding your knowledge!

![](/files/3scdgQ104Am6SpMHEVcF)


# Ecosystem

Boosting results with enhanced capabilities

Add-ons are optional, yet powerful extensions to the Result library, designed to provide extra features that can be integrated on demand.

These small, focused libraries provide a modular approach to extending the core functionalities of Results without adding unnecessary complexity.

<table data-view="cards" data-full-width="true"><thead><tr><th></th><th data-hidden data-card-target data-type="content-ref"></th><th data-hidden data-card-cover data-type="image">Cover image</th><th data-hidden data-card-cover-dark data-type="image">Cover image (dark)</th></tr></thead><tbody><tr><td>Write expressive assertions using <a href="https://assertj.github.io/"><strong>AssertJ</strong></a></td><td><a href="/pages/qSR3nx6gmpph3cRO8O51">/pages/qSR3nx6gmpph3cRO8O51</a></td><td data-object-fit="contain"><a href="/files/bpQVRtfP9WKEKO5pwgcR">/files/bpQVRtfP9WKEKO5pwgcR</a></td><td><a href="/files/mPGjqAswrx1gejSR1j7z">/files/mPGjqAswrx1gejSR1j7z</a></td></tr><tr><td>Serialize and deserialize results using <a href="https://github.com/FasterXML/jackson"><strong>Jackson</strong></a></td><td><a href="/pages/piOZkyDIOXySq44ajtlT">/pages/piOZkyDIOXySq44ajtlT</a></td><td data-object-fit="contain"><a href="/files/7BfrAYOTIVm3sdyfc2sx">/files/7BfrAYOTIVm3sdyfc2sx</a></td><td><a href="/files/BOkHI7rVUsQyopNckPes">/files/BOkHI7rVUsQyopNckPes</a></td></tr><tr><td>Serialize and deserialize results using <a href="https://github.com/micronaut-projects/micronaut-serialization"><strong>Micronaut Serialization</strong></a></td><td><a href="/pages/VqHF68pFGKdV4ojYbMxl">/pages/VqHF68pFGKdV4ojYbMxl</a></td><td data-object-fit="contain"><a href="/files/JgEq5Hpq45nkp8JjCnfW">/files/JgEq5Hpq45nkp8JjCnfW</a></td><td><a href="/files/sPsc7OitvZsiVeuAjmxw">/files/sPsc7OitvZsiVeuAjmxw</a></td></tr></tbody></table>


# Fluent Assertions

How to assert Result objects fluently

You can use fluent assertions for Result objects to enhance the readability and expressiveness of your unit tests. These assertions are based on [AssertJ](https://assertj.github.io/), an open-source Java library that offers a fluent API for writing assertions in test cases.

{% hint style="info" %}
[AssertJ](https://assertj.github.io/) features a comprehensive and intuitive set of strongly-typed assertions for unit testing. It is a popular choice among Java developers due to its effective features and compatibility with various testing frameworks like [JUnit](https://junit.org/) and [TestNG](https://testng.org/).
{% endhint %}

## How to Use this Add-On

Add this Maven dependency to your build:

| Group ID                | Artifact ID      | Latest Version                                                                                        |
| ----------------------- | ---------------- | ----------------------------------------------------------------------------------------------------- |
| `com.leakyabstractions` | `result-assertj` | ![](https://img.shields.io/endpoint?url=https://dev.leakyabstractions.com/result-assertj/latest.json) |

{% hint style="success" %}
[Maven Central](https://central.sonatype.com/artifact/com.leakyabstractions/result-assertj/) provides snippets for different build tools to declare this dependency.
{% endhint %}

## Asserting Result Objects

You can use [`ResultAssertions::assertThat`](https://javadoc.io/doc/com.leakyabstractions/result-assertj/latest/com/leakyabstractions/result/assertj/ResultAssertions.html#assertThat-com.leakyabstractions.result.api.Result-) in your tests to create fluent assertions for result objects.

```java
import static com.leakyabstractions.result.assertj.ResultAssertions.assertThat;

@Test
void testAssertThat() {
  // Given
  final int zero = 0;
  // When
  final Result<Integer, String> result = success(zero);
  // Then
  assertThat(zero).isZero();
  assertThat(result).hasSuccess(zero);
}
```

If, for any reason, you cannot statically import `assertThat`, you can use [`ResultAssert::assertThatResult`](https://javadoc.io/doc/com.leakyabstractions/result-assertj/latest/com/leakyabstractions/result/assertj/ResultAssert.html#assertThatResult-com.leakyabstractions.result.api.Result-) instead.

```java
import static com.leakyabstractions.result.assertj.ResultAssert.assertThatResult;
import static org.assertj.core.api.Assertions.assertThat;

@Test
void testAssertThatResult() {
  // Given
  final int zero = 0;
  // When
  final Result<Integer, String> result = success(zero);
  // Then
  assertThat(zero).isZero();
  assertThatResult(result).hasSuccess(zero);
}
```

## Conclusion

We covered how to use fluent assertions for Results. This approach allows you to write clear and expressive tests, enhancing the maintainability of your unit tests while ensuring that Result objects behave as expected.

{% hint style="success" %}
The full source code for the examples is [available on GitHub](https://github.com/LeakyAbstractions/result-assertj/tree/main/result-assertj/src/test/java/example).
{% endhint %}


# Jackson Modules

How to serialize Result objects with Jackson 2.x and 3.x

When using Result objects with [**Jackson**](https://github.com/FasterXML/jackson/) we might run into some problems. The Jackson datatype modules for Result solve them by making Jackson treat results as if they were ordinary objects.

{% hint style="info" %}
[**Jackson**](https://github.com/FasterXML/jackson/) is a Java library for [JSON](https://www.json.org/) parsing and generation. It is widely used for converting Java objects to JSON and vice versa, making it essential for handling data in web services and RESTful APIs.
{% endhint %}

## How to Use These Add-Ons

Choose the Maven dependency that matches your Jackson version.

### Jackson 2.x

Add this Maven dependency to your build:

| Group ID                | Artifact ID      | Latest Version                                                                                        |
| ----------------------- | ---------------- | ----------------------------------------------------------------------------------------------------- |
| `com.leakyabstractions` | `result-jackson` | ![](https://img.shields.io/endpoint?url=https://dev.leakyabstractions.com/result-jackson/latest.json) |

### Jackson 3.x

Add this one instead:

| Group ID                | Artifact ID       | Latest Version                                                                                         |
| ----------------------- | ----------------- | ------------------------------------------------------------------------------------------------------ |
| `com.leakyabstractions` | `result-jackson3` | ![](https://img.shields.io/endpoint?url=https://dev.leakyabstractions.com/result-jackson3/latest.json) |

{% hint style="success" %}
Maven Central provides snippets for different build tools to declare these dependencies.

* [Jackson 2.x datatype module for Result](https://central.sonatype.com/artifact/com.leakyabstractions/result-jackson/)
* [Jackson 3.x datatype module for Result](https://central.sonatype.com/artifact/com.leakyabstractions/result-jackson3/)
  {% endhint %}

## Test Scenario

Let's start by creating a class `ApiResponse` containing one ordinary and one `Result` field.

```java
/** Represents an API response */
public class ApiResponse {

  @JsonProperty
  String version;

  @JsonProperty
  Result<String, String> result;

  // Constructors, getters and setters omitted
}
```

## Problem Overview

Then we will take a look at what happens when we try to serialize and deserialize `ApiResponse` objects.

### Serialization Problem (Jackson 2.x Only)

Now, let's instantiate an `ApiResponse` object.

```java
ApiResponse response = new ApiResponse();
response.setVersion("v1");
response.setResult(success("Perfect"));
```

And finally, let's try serializing it using an [object mapper](https://www.baeldung.com/jackson-object-mapper-tutorial).

```java
ObjectMapper objectMapper = new ObjectMapper();
String json = objectMapper.writeValueAsString(response);
```

With Jackson 2.x, this will produce an error: [`InvalidDefinitionException`](https://javadoc.io/static/com.fasterxml.jackson.core/jackson-databind/2.17.2/com/fasterxml/jackson/databind/exc/InvalidDefinitionException.html).

```
Java 8 optional type `java.util.Optional<java.lang.String>`
 not supported by default:
 add Module "com.fasterxml.jackson.datatype:jackson-datatype-jdk8"
 to enable handling
```

The reason is Jackson encounters `Optional` values internally and it will not handle it unless you register [the appropriate modules](https://github.com/FasterXML/jackson-modules-java8/).

### Deserialization Problem (Both Jackson 2.x and 3.x)

Now, let's reverse our previous example, this time trying to deserialize a JSON object into an `ApiResponse`.

```java
String json = "{\"version\":\"v2\",\"result\":{\"success\":\"OK\"}}";
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.readValue(json, ApiResponse.class);
```

This will produce an error: [`InvalidDefinitionException`](https://javadoc.io/static/com.fasterxml.jackson.core/jackson-databind/2.17.2/com/fasterxml/jackson/databind/exc/InvalidDefinitionException.html). Let's inspect the stack trace.

```
Cannot construct instance of `com.leakyabstractions.result.api.Result`
 (no Creators, like default constructor, exist):
 abstract types either need to be mapped to concrete types,
 have custom deserializer, or contain additional type information
```

This behavior again makes sense. Essentially, Jackson cannot create new result objects because `Result` is an interface, not a concrete type.

## Solution Implementation

The Jackson datatype modules for Result provide serializers and deserializers so that Jackson treats results as if they were regular objects.

### Registering the Jackson Datatype Module for Result

First of all, we need to [add the the appropriate datatype module as a dependency](#how-to-use-this-add-on).

#### Jackson 2.x

Then, all we need to do is register `ResultModule` with our [object mapper](https://www.baeldung.com/jackson-object-mapper-tutorial).

```java
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new ResultModule());
```

Alternatively, you can also make Jackson 2.x auto-discover the module.

```java
objectMapper.findAndRegisterModules();
```

#### Jackson 3.x

Just like the previous example, we need to add `ResultModule` to our [JSON mapper](https://javadoc.io/static/tools.jackson.core/jackson-databind/3.0.0/tools.jackson.databind/tools/jackson/databind/json/JsonMapper.html).

```java
JsonMapper.Builder builder = JsonMapper.builder();
builder.addModule(new ResultModule());
ObjectMapper objectMapper = builder.build();
```

Or simply use auto-discovery:

```java
builder.findAndAddModules();
```

{% hint style="info" %}
Regardless of the chosen registration mechanism, once the appropriate dataype module is registered all functionality is available for all normal Jackson operations.
{% endhint %}

### Serializing Results

Now, let's try and serialize our `ApiResponse` object again:

```java
@Test
void serializeSuccessfulResult() throws Exception {
  // Given
  ApiResponse response = new ApiResponse("v3", success("All good"));
  // When
  ObjectMapper objectMapper = new ObjectMapper();
  objectMapper.registerModule(new ResultModule());
  String json = objectMapper.writeValueAsString(response);
  // Then
  assertTrue(json.contains("v3"));
  assertTrue(json.contains("All good"));
}
```

If we look at the serialized response, we'll see that this time the `result` field contains a null `failure` value and a non-null `success` value:

```json
{
  "version": "v3",
  "result": {
    "failure": null,
    "success": "All good"
  }
}
```

Next, we can try serializing a failed result.

```java
@Test
void serializeFailedResult() throws Exception {
  // Given
  ApiResponse response = new ApiResponse("v4", failure("Oops"));
  // When
  ObjectMapper objectMapper = new ObjectMapper();
  objectMapper.findAndRegisterModules();
  String json = objectMapper.writeValueAsString(response);
  // Then
  assertTrue(json.contains("v4"));
  assertTrue(json.contains("Oops"));
} // End
```

We can verify that the serialized response contains a non-null `failure` value and a null `success` value.

```json
{
  "version": "v4",
  "result": {
    "failure": "Oops",
    "success": null
  }
}
```

### Deserializing Results

Now, let's repeat our tests for deserialization. If we read our `ApiResponse` again, we'll see that we no longer get an [`InvalidDefinitionException`](https://javadoc.io/static/com.fasterxml.jackson.core/jackson-databind/2.17.2/com/fasterxml/jackson/databind/exc/InvalidDefinitionException.html).

```java
@Test
void deserializeSuccessfulResult() {
  // Given
  String json = "{\"version\":\"v5\",\"result\":{\"success\":\"Yay\"}}";
  // When
  ObjectMapper objectMapper = new ObjectMapper().findAndRegisterModules();
  ApiResponse response = objectMapper.readValue(json, ApiResponse.class);
  // Then
  assertEquals("v5", response.getVersion());
  assertEquals("Yay", response.getResult().orElse(null));
}
```

Finally, let's repeat the test again, this time with a failed result. We'll see that yet again we don't get an exception, and in fact, have a failed result.

```java
@Test
void deserializeFailedResult() {
  // Given
  String json = "{\"version\":\"v6\",\"result\":{\"failure\":\"Nay\"}}";
  // When
  ObjectMapper objectMapper = new ObjectMapper().findAndRegisterModules();
  ApiResponse response = objectMapper.readValue(json, ApiResponse.class);
  // Then
  assertEquals("v6", response.getVersion());
  assertEquals("Nay", response.getResult().getFailure().orElse(null));
}
```

## Conclusion

We learned how to serialize and deserialize Result objects using both **Jackson 2.x** and **Jackson 2.x**, demonstrating how the provided datatype module enables Jackson to treat Results as ordinary objects.

The integration is nearly identical across versions; the main differences are limited to dependency coordinates and how the object mapper is constructed and configured.

{% hint style="success" %}
The full source code for the examples is available on GitHub.

* [Jackson 2.x examples](https://github.com/LeakyAbstractions/result-jackson/tree/main/result-jackson/src/test/java/example)
* [Jackson 3.x examples](https://github.com/LeakyAbstractions/result-jackson3/tree/main/result-jackson3/src/test/java/example)
  {% endhint %}


# Micronaut Serialization

How to serialize Result objects with Micronaut

When using Result objects with [Micronaut](https://micronaut.io/), we might run into some problems. The [Micronaut serialization](https://micronaut-projects.github.io/micronaut-serialization/latest/guide/) support for Result solves them by making Micronaut treat results as [`Serdeable`](https://javadoc.io/doc/io.micronaut.serde/micronaut-serde-api/latest/io/micronaut/serde/annotation/Serdeable.html) (so they can be serialized and deserialized).

{% hint style="info" %}
[Micronaut](https://micronaut.io/) is a modern, JVM-based framework for building lightweight microservices and serverless applications. It focuses on fast startup times and low memory usage. Although not as widely adopted as [Spring Boot](https://spring.io/projects/spring-boot), it has gained popularity for its performance and innovative features.
{% endhint %}

## How to Use this Add-On

Add this Maven dependency to your build:

| Group ID                | Artifact ID              | Latest Version                                                                                                |
| ----------------------- | ------------------------ | ------------------------------------------------------------------------------------------------------------- |
| `com.leakyabstractions` | `result-micronaut-serde` | ![](https://img.shields.io/endpoint?url=https://dev.leakyabstractions.com/result-micronaut-serde/latest.json) |

{% hint style="success" %}
[Maven Central](https://central.sonatype.com/artifact/com.leakyabstractions/result-micronaut-serde/) provides snippets for different build tools to declare this dependency.
{% endhint %}

## Test Scenario

Let's start by creating a record `ApiOperation` containing one ordinary and one Result field.

```java
/** Represents an API operation */
@Serdeable
public record ApiOperation(String name, Result<String, String> result) {
}
```

## Problem Overview

We will take a look at what happens when we try to serialize and deserialize `ApiOperation` objects with Micronaut.

### Serialization Problem

Now, let's create a Micronaut controller that returns an instance of `ApiOperation` containing a successful result.

```java
@Controller("/operations")
public class ApiController {

    @Get("/last")
    ApiOperation lastOperation() {
        return new ApiOperation("setup", Results.success("Perfect"));
    }
}
```

And finally, let's run the application and try the `/operations/last` endpoint we just created.

```bash
curl 'http://localhost:8080/operations/last'
```

We'll see that we get a Micronaut `CodecException` caused by a [`SerdeException`](https://javadoc.io/doc/io.micronaut.serde/micronaut-serde-api/latest/io/micronaut/serde/exceptions/SerdeException.html).

```
No serializable introspection present for type Success.
 Consider adding Serdeable. Serializable annotate to type Success.
 Alternatively if you are not in control of the project's source code,
 you can use @SerdeImport(Success.class) to enable serialization of this type.
```

Although this may look strange, it's actually what we should expect. Even though we annotated `ApiOperation` as [`@Serdeable`](https://javadoc.io/doc/io.micronaut.serde/micronaut-serde-api/latest/io/micronaut/serde/annotation/Serdeable.html), Micronaut doesn't know how to serialize result objects yet, so the data structure cannot be serialized.

```java
@Test
void testSerializationProblem(ObjectMapper objectMapper) {
  // Given
  ApiOperation op = new ApiOperation("setup", success("Perfect"));
  // Then
  SerdeException error = assertThrows(SerdeException.class,
      () -> objectMapper.writeValueAsString(op));
  assertTrue(error.getMessage().startsWith(
      "No serializable introspection present for type Success."));
}
```

This is Micronaut's default serialization behavior. But we'd like to serialize the `result` field like this:

```json
{
  "name": "setup",
  "result": {
    "failure": null,
    "success": "Perfect"
  }
}
```

### Deserialization Problem

Now, let's reverse our previous example, this time trying to receive an `ApiOperation` as the body of a `POST` request.

```java
@Controller("/operations")
public class ApiController {

    @Post("/notify")
    Map<String, String> notify(@Body ApiOperation op) {
        return op.result()
                .mapSuccess(s -> Map.of("message", op.name() + " succeeded: " + s))
                .orElseMap(f -> Map.of("error", op.name() + " failed: " + f));
    }
}
```

We'll see that now we get an [`IntrospectionException`](https://javadoc.io/doc/io.micronaut/micronaut-core/latest/io/micronaut/core/beans/exceptions/IntrospectionException.html). Let's inspect the stack trace.

```
No bean introspection available for type
 [interface com.leakyabstractions.result.api.Result].
 Ensure the class is annotated with
 io.micronaut.core.annotation.Introspected
```

This behavior again makes sense. Essentially, Micronaut cannot create new result objects, because `Result` is not annotated as [`@Introspected`](https://javadoc.io/doc/io.micronaut/micronaut-core/latest/io/micronaut/core/annotation/Introspected.html) or [`@Serdeable`](https://javadoc.io/doc/io.micronaut.serde/micronaut-serde-api/latest/io/micronaut/serde/annotation/Serdeable.html).

```java
@Test
void testDeserializationProblem(ObjectMapper objectMapper) {
  // Given
  String json = """
      {"name":"renew","result":{"success":"OK"}}""";
  // Then
  IntrospectionException error = assertThrows(IntrospectionException.class,
      () -> objectMapper.readValue(json, ApiOperation.class));
  String errorMessage = error.getMessage(); // Extract error message
  // Verify error message
  assertTrue(errorMessage.startsWith("No bean introspection available " +
      "for type [interface com.leakyabstractions.result.api.Result]."));
} // End
```

## Solution Implementation

What we want, is for Micronaut to treat Result values as JSON objects that contain either a `success` or a `failure` value. Fortunately, there's an easy way to solve this problem.

### Adding the Serde Imports to the Classpath

All we need to do now is [add Result-Micronaut-Serde as a Maven dependency](#how-to-use-this-add-on). Once the [`@SerdeImport`](https://javadoc.io/doc/io.micronaut.serde/micronaut-serde-api/latest/io/micronaut/serde/annotation/SerdeImport.html) is in the classpath, all functionality is available for all normal Micronaut operations.

### Serializing Results

Now, let's try and serialize our `ApiOperation` object again.

```java
@Test
void serializeSuccessfulResult(ObjectMapper objectMapper)
    throws IOException {
  // Given
  ApiOperation op = new ApiOperation("clean", success("All good"));
  // When
  String json = objectMapper.writeValueAsString(op);
  // Then
  assertEquals("""
      {"name":"clean","result":{"success":"All good"}}""", json);
}
```

If we look at the serialized response, we'll see that this time the `result` field contains a `success` field.

```json
{
  "name": "clean",
  "result": {
    "failure": null,
    "success": "All good"
  }
}
```

Next, we can try serializing a failed result.

```java
@Test
void serializeFailedResult(ObjectMapper objectMapper)
    throws IOException {
  // Given
  ApiOperation op = new ApiOperation("build", failure("Oops"));
  // When
  String json = objectMapper.writeValueAsString(op);
  // Then
  assertEquals("""
      {"name":"build","result":{"failure":"Oops"}}""", json);
}
```

We can verify that the serialized response contains a non-null `failure` value and a null `success` value:

```json
{
  "name": "build",
  "result": {
    "failure": "Oops",
    "success": null
  }
}
```

### Deserializing Results

Now, let's repeat our tests for deserialization. If we read our `ApiOperation` again, we'll see that we no longer get an [`IntrospectionException`](https://javadoc.io/doc/io.micronaut/micronaut-core/latest/io/micronaut/core/beans/exceptions/IntrospectionException.html).

```java
@Test
void deserializeSuccessfulResult(ObjectMapper objectMapper)
    throws IOException {
  // Given
  String json = """
      {"name":"check","result":{"success":"Yay"}}""";
  // When
  ApiOperation response = objectMapper.readValue(json, ApiOperation.class);
  // Then
  assertEquals("check", response.name());
  assertEquals("Yay", response.result().orElse(null));
}
```

Finally, let's repeat the test again, this time with a failed result. We'll see that yet again we don't get an exception, and in fact, have a failed result.

```java
@Test
void deserializeFailedResult(ObjectMapper objectMapper)
    throws IOException {
  // Given
  String json = """
      {"name":"start","result":{"failure":"Nay"}}""";
  // When
  ApiOperation response = objectMapper.readValue(json, ApiOperation.class);
  // Then
  assertEquals("start", response.name());
  assertEquals("Nay", response.result().getFailure().orElse(null));
}
```

## Conclusion

We learned how to serialize and deserialize Result objects using [Micronaut](https://micronaut.io/), demonstrating how the provided [`@SerdeImport`](https://javadoc.io/doc/io.micronaut.serde/micronaut-serde-api/latest/io/micronaut/serde/annotation/SerdeImport.html) enables Micronaut to treat Results as [`Serdeable`](https://javadoc.io/doc/io.micronaut.serde/micronaut-serde-api/latest/io/micronaut/serde/annotation/Serdeable.html) objects.

{% hint style="success" %}
The full source code for the examples is [available on GitHub](https://github.com/LeakyAbstractions/result-micronaut-serde/tree/main/result-micronaut-serde/src/test/java/example).
{% endhint %}


# Lazy Results

How to defer expensive calculations with Results

Lazy results optimize performance by deferring costly operations until absolutely necessary. They behave like regular results, but only execute the underlying operation when an actual check for success or failure is performed.

## How to Use this Add-On

Add this Maven dependency to your build:

| Group ID                | Artifact ID   | Latest Version                                                                                     |
| ----------------------- | ------------- | -------------------------------------------------------------------------------------------------- |
| `com.leakyabstractions` | `result-lazy` | ![](https://img.shields.io/endpoint?url=https://dev.leakyabstractions.com/result-lazy/latest.json) |

{% hint style="success" %}
[Maven Central](https://central.sonatype.com/artifact/com.leakyabstractions/result-lazy/) provides snippets for different build tools to declare this dependency.
{% endhint %}

## Creating Lazy Results

We can use [`LazyResults::ofSupplier`](https://javadoc.io/doc/com.leakyabstractions/result-lazy/latest/com/leakyabstractions/result/lazy/LazyResults.html#ofSupplier-java.util.function.Supplier-) to create a lazy result.

```java
Supplier<Result<Integer, String>> supplier = () -> success(123);
Result<Integer, String> lazy = LazyResults.ofSupplier(supplier);
```

While [suppliers](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/function/Supplier.html) can return a fixed success or failure, lazy results shine when they encapsulate time-consuming or resource-intensive operations.

```java
/* Represents the operation we may omit */
Result<Long, Exception> expensiveCalculation(AtomicLong timesExecuted) {
  long counter = timesExecuted.incrementAndGet();
  return success(counter);
}
```

This sample method simply increments and returns a counter for brevity. However, in a typical scenario, this would involve an I/O operation.

## Skipping Expensive Calculations

The advantage of lazy results is that they defer invoking the provided [`Supplier`](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/function/Supplier.html) for as long as possible. Despite this, you can screen and transform them like any other result without losing their laziness.

```java
@Test
void shouldSkipExpensiveCalculation() {
  AtomicLong timesExecuted = new AtomicLong();
  // Given
  Result<Long, Exception> lazy = LazyResults
      .ofSupplier(() -> expensiveCalculation(timesExecuted));
  // When
  Result<String, Exception> transformed = lazy.mapSuccess(Object::toString);
  // Then
  assertNotNull(transformed);
  assertEquals(0L, timesExecuted.get());
}
```

In this example, the expensive calculation is omitted because the lazy result is never fully evaluated. This test demonstrates that a lazy result can be transformed while maintaining laziness, ensuring that the expensive calculation is deferred.

{% hint style="info" %}
These methods will preserve laziness:

* [`Result::filter`](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#filter-java.util.function.Predicate-java.util.function.Function-)
* [`Result::recover`](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#recover-java.util.function.Predicate-java.util.function.Function-)
* [`Result::mapSuccess`](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#mapSuccess-java.util.function.Function-)
* [`Result::mapFailure`](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#mapFailure-java.util.function.Function-)
* [`Result::map`](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#map-java.util.function.Function-java.util.function.Function-)
* [`Result::flatMapSuccess`](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#flatMapSuccess-java.util.function.Function-)
* [`Result::flatMapFailure`](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#flatMapFailure-java.util.function.Function-)
* [`Result::flatMap`](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#flatMap-java.util.function.Function-java.util.function.Function-)
  {% endhint %}

## Triggering Result Evaluation

Finally, when it's time to check whether the operation succeeds or fails, the lazy result will execute it. This is triggered by using any of the *terminal* methods, such as [`Result::hasSuccess`](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#hasSuccess--).

```java
@Test
void shouldExecuteExpensiveCalculation() {
  AtomicLong timesExecuted = new AtomicLong();
  // Given
  Result<Long, Exception> lazy = LazyResults
      .ofSupplier(() -> expensiveCalculation(timesExecuted));
  // When
  Result<String, Exception> transformed = lazy.mapSuccess(Object::toString);
  boolean success = transformed.hasSuccess();
  // Then
  assertTrue(success);
  assertEquals(1L, timesExecuted.get());
}
```

Here, the expensive calculation is executed because the lazy result is finally evaluated.

{% hint style="info" %}
Terminal methods will immediately evaluate the lazy result:

* [`Result::hasSuccess`](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#hasSuccess--)
* [`Result::hasFailure`](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#hasFailure--)
* [`Result::getSuccess`](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#getSuccess--)
* [`Result::getFailure`](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#getFailure--)
* [`Result::orElse`](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#orElse-S-)
* [`Result::orElseMap`](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#orElseMap-java.util.function.Function-)
* [`Result::streamSuccess`](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#streamSuccess--)
* [`Result::streamFailure`](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#streamFailure--)
  {% endhint %}

## Handling Success and Failure Eagerly

By default, [`Result::ifSuccess`](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#ifSuccess-java.util.function.Consumer-), [`Result::ifFailure`](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#ifFailure-java.util.function.Consumer-), and [`Result::ifSuccessOrElse`](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#ifSuccessOrElse-java.util.function.Consumer-java.util.function.Consumer-) are treated as terminal methods. This means they eagerly evaluate the result and then perform an action based on its status.

```java
@Test
void shouldHandleSuccessEagerly() {
  AtomicLong timesExecuted = new AtomicLong();
  AtomicLong consumerExecuted = new AtomicLong();
  Consumer<Long> consumer = x -> consumerExecuted.incrementAndGet();
  // Given
  Result<Long, Exception> lazy = LazyResults
      .ofSupplier(() -> expensiveCalculation(timesExecuted));
  // When
  lazy.ifSuccess(consumer);
  // Then
  assertEquals(1L, timesExecuted.get());
  assertEquals(1L, consumerExecuted.get());
}
```

In this test, we don't explicitly *unwrap the value* or *check the status*, but since we want to *consume the success value*, we need to evaluate the lazy result first.

Furthermore, even if we wanted to handle the failure scenario, we would still need to evaluate the lazy result.

```java
@Test
void shouldHandleFailureEagerly() {
  AtomicLong timesExecuted = new AtomicLong();
  AtomicLong consumerExecuted = new AtomicLong();
  Consumer<Exception> consumer = x -> consumerExecuted.incrementAndGet();
  // Given
  Result<Long, Exception> lazy = LazyResults
      .ofSupplier(() -> expensiveCalculation(timesExecuted));
  // When
  lazy.ifFailure(consumer);
  // Then
  assertEquals(1L, timesExecuted.get());
  assertEquals(0L, consumerExecuted.get());
}
```

In this other test, we use [`Result::ifFailure`](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#ifFailure-java.util.function.Consumer-) instead of [`Result::ifSuccess`](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#ifSuccess-java.util.function.Consumer-). Since the lazy result is evaluated to a success, the failure consumer is never executed.

{% hint style="info" %}
These methods are treated as terminal when used with regular consumer functions:

* [`Result::ifSuccess`](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#ifSuccess-java.util.function.Consumer-)
* [`Result::ifFailure`](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#ifFailure-java.util.function.Consumer-)
* [`Result::ifSuccessOrElse`](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#ifSuccessOrElse-java.util.function.Consumer-java.util.function.Consumer-)
  {% endhint %}

## Handling Success and Failure Lazily

When these conditional actions may also be skipped along with the expensive calculation, we can encapsulate them into a [`LazyConsumer`](https://javadoc.io/doc/com.leakyabstractions/result-lazy/latest/com/leakyabstractions/result/lazy/LazyConsumer.html) instead of a regular [`Consumer`](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/function/Consumer.html). All we need to do is to create the consumer using [`LazyConsumer::of`](https://javadoc.io/doc/com.leakyabstractions/result-lazy/latest/com/leakyabstractions/result/lazy/LazyConsumer.html#of-java.util.function.Consumer-). Lazy consumers will preserve the laziness until a terminal method is eventually used on the result.

```java
@Test
void shouldHandleSuccessLazily() {
  AtomicLong timesExecuted = new AtomicLong();
  AtomicLong consumerExecuted = new AtomicLong();
  Consumer<Long> consumer = LazyConsumer
      .of(x -> consumerExecuted.incrementAndGet());
  // Given
  Result<Long, Exception> lazy = LazyResults
      .ofSupplier(() -> expensiveCalculation(timesExecuted));
  // When
  lazy.ifSuccess(consumer);
  // Then
  assertEquals(0L, timesExecuted.get());
  assertEquals(0L, consumerExecuted.get());
}
```

Here, we use a lazy consumer with [`Result::ifSuccess`](https://javadoc.io/doc/com.leakyabstractions/result-api/latest/com/leakyabstractions/result/api/Result.html#ifSuccess-java.util.function.Consumer-) so the expensive calculation is skipped because the lazy result is never fully evaluated.

## Conclusion

We learned how to defer expensive calculations until absolutely necessary. By leveraging lazy results, you can optimize performance by avoiding unnecessary computations and only evaluating the operation's outcome when needed.

{% hint style="success" %}
The full source code for the examples is [available on GitHub](https://github.com/LeakyAbstractions/result-lazy/tree/main/result-lazy/src/test/java/example).
{% endhint %}


# Bill of Materials

How to declare dependencies without having to worry about version numbers

Tracking multiple add-on versions for your project can quickly become cumbersome. In that situation, you can use the convenient [Result Library Bill of Materials](https://github.com/LeakyAbstractions/result-bom) to centralize and align their versions. This ensures compatibility and simplifies dependency maintenance.

{% hint style="info" %}
[Maven](https://maven.apache.org/)'s Bill of Materials POMs are special POM files that group dependency versions known to be valid and tested to work together, reducing the chances of having version mismatches.
{% endhint %}

The basic idea is that instead of specifying a version number for each Result library in your project, you can use this BOM to get a complete set of consistent versions.

## How to Use this Add-On

Add this Maven dependency to your build:

| Group ID                | Artifact ID  | Latest Version                                                                                    |
| ----------------------- | ------------ | ------------------------------------------------------------------------------------------------- |
| `com.leakyabstractions` | `result-bom` | ![](https://img.shields.io/endpoint?url=https://dev.leakyabstractions.com/result-bom/latest.json) |

### Maven

To [import the BOM using Maven](https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#bill-of-materials-bom-poms), use the following:

```xml
<!-- Import the BOM -->
<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>com.leakyabstractions</groupId>
      <artifactId>result-bom</artifactId>
      <version>1.0.0.0</version>
      <scope>import</scope>
      <type>pom</type>
    </dependency>
  </dependencies>
</dependencyManagement>

<!-- Define dependencies without version numbers -->
<dependencies>
  <dependency>
    <groupId>com.leakyabstractions</groupId>
    <artifactId>result</artifactId>
  </dependency>
  <dependency>
    <groupId>com.leakyabstractions</groupId>
    <artifactId>result-assertj</artifactId>
    <scope>test</scope>
  </dependency>
</dependencies>
```

### Gradle

To [import the BOM using Gradle](https://docs.gradle.org/current/userguide/platforms.html#sub:bom_import), use the following:

```groovy
dependencies {
  // Import the BOM
  implementation platform("com.leakyabstractions:result-bom:1.0.0.0")

  // Define dependencies without version numbers
  implementation("com.leakyabstractions:result")
  testImplementation("com.leakyabstractions:result-assertj")
}
```

## Conclusion

We discussed the benefits of using the Bill of Materials for managing dependencies in your project. With the BOM, you can eliminate the hassle of manually specifying version numbers, ensuring consistency and compatibility across all Result libraries.


# Benchmarks

Measuring performance to find out how fast Results are

Throughout these guides, we have mentioned that throwing Java exceptions is slow. But... how slow? According to our benchmarks, throwing an exception is several orders of magnitude slower than returning a failed result.

![Returning a failed Result object is significantly faster than throwing an exception.](https://img.shields.io/endpoint?url=https://dev.leakyabstractions.com/result-benchmark/badge.json)

This proves that using exceptional logic just to control normal program flow is a bad idea.

{% hint style="info" %}
We should throw exceptions sparingly, even more so when developing performance-critical applications.
{% endhint %}

## Benchmarking Result Library

This library comes with [a set of benchmarks that compare performance](https://github.com/LeakyAbstractions/result-benchmark) when using results versus when using exceptions.

### Simple Scenarios

The first scenarios compare the most basic usage: a method that returns a `String` or fails, depending on a given `int` parameter:

#### Using Exceptions

```java
public String usingExceptions(int number) throws SimpleException {
  if (number < 0) {
    throw new SimpleException(number);
  }
  return "ok";
}
```

#### Using Results

```java
public Result<String, SimpleFailure> usingResults(int number) {
  if (number < 0) {
    return Results.failure(new SimpleFailure(number));
  }
  return Results.success("ok");
}
```

### Complex Scenarios

The next scenarios do something a little bit more elaborate: a method invokes the previous method to retrieve a `String`; if successful, then converts it to upper case; otherwise transforms the "simple" error into a "complex" error.

#### Using Exceptions

```java
public String usingExceptions(int number) throws ComplexException {
  try {
    return simple.usingExceptions(number).toUpperCase();
  } catch (SimpleException e) {
    throw new ComplexException(e);
  }
}
```

#### Using Results

```java
public Result<String, ComplexFailure> usingResults(int number) {
  return simple.usingResults(number)
    .map(String::toUpperCase, ComplexFailure::new);
}
```

## Conclusion

We provided insights into the Result library's performance through benchmarking. While our metrics corroborate that most codebases could benefit from using this library instead of throwing exceptions, its main goal is to help promote best practices and implement proper error handling.

{% hint style="info" %}
To address performance concerns, benchmark your applications to gain reusable insights. These should guide your decisions on selecting frameworks and libraries.
{% endhint %}


# Demo Projects

Check out some REST APIs that consume and produce Result objects

To help you become familiar with this library, you can explore two demo projects that showcase how to handle and serialize Result objects within popular frameworks like [**Spring Boot**](https://spring.io/projects/spring-boot) and [**Micronaut**](https://micronaut.io/). Each project provides a working example of a "pet store" web service that exposes a REST API for managing pets. They are based on [Swagger Petstore Sample](https://github.com/swagger-api/swagger-petstore) and you can interact with them using [**Swagger-UI**](https://github.com/swagger-api/swagger-ui).

<table data-card-size="large" data-view="cards" data-full-width="true"><thead><tr><th></th><th align="center"></th><th data-hidden data-card-cover data-type="image">Cover image</th><th data-hidden data-card-cover-dark data-type="image">Cover image (dark)</th></tr></thead><tbody><tr><td><a href="https://spring.io/projects/spring-boot"><strong>Spring Boot</strong></a> is a widely-used, JVM-based framework designed to simplify the development of stand-alone, production-ready Spring applications. It emphasizes convention over configuration, allowing developers to get started quickly with minimal setup and leveraging the powerful <a href="https://spring.io/"><strong>Spring Framework</strong></a> while minimizing boilerplate code.</td><td align="center"><a href="https://github.com/LeakyAbstractions/result-example-spring-boot" class="button primary" data-icon="rocket-launch">Try it in 5 minutes</a></td><td data-object-fit="contain"><a href="/files/Rg7gUvcBAqbr6MWrGFOi">/files/Rg7gUvcBAqbr6MWrGFOi</a></td><td></td></tr><tr><td><a href="https://micronaut.io/"><strong>Micronaut</strong></a> is a modern, JVM-based framework for building lightweight microservices and serverless applications. It focuses on fast startup times and low memory usage. Although not as widely adopted as <a href="https://spring.io/projects/spring-boot">Spring Boot</a>, it has gained popularity for its performance and innovative features.</td><td align="center"><a href="https://github.com/LeakyAbstractions/result-example-micronaut" class="button primary" data-icon="rocket-launch">Try it in 5 minutes</a></td><td data-object-fit="contain"><a href="/files/JgEq5Hpq45nkp8JjCnfW">/files/JgEq5Hpq45nkp8JjCnfW</a></td><td><a href="/files/sPsc7OitvZsiVeuAjmxw">/files/sPsc7OitvZsiVeuAjmxw</a></td></tr></tbody></table>

These projects illustrate how to develop powerful APIs using Result objects. Follow the examples to create resilient web services that elegantly handle success and failure scenarios.


# Spring Boot Demo Project

Take a look at a Spring Boot-based REST API leveraging Result objects

This demo project demonstrates how to handle and serialize `Result` objects within a [Spring Boot](https://spring.io/projects/spring-boot) application. It provides a working example of a "pet store" web service that exposes a REST API for managing pets.

## Generating the Project

The project was generated via [Spring Initializr](https://start.spring.io/) including features: *web* and *cloud-feign*.

## Adding Serialization Support

Then [Jackson datatype module for Result objects](/add-ons/jackson) was manually added as a dependency to serialize and deserialize `Result` objects.

{% code title="build.gradle" %}

```groovy
dependencies {
  // ...
  implementation platform('com.leakyabstractions:result-bom:1.0.0.0')
  implementation 'com.leakyabstractions:result'
  implementation 'com.leakyabstractions:result-jackson'
}
```

{% endcode %}

We use a `@Bean` to register the datatype module.

{% code title="JacksonConfig.java" %}

```java
@Configuration
public class JacksonConfig {
  @Bean
  public Module registerResultModule() {
    return new ResultModule();
  }
}
```

{% endcode %}

## API Responses

API responses contain a `Result` field, encapsulating the outcome of the requested operation.

{% code title="ApiResponse.java" %}

```java
public class ApiResponse<S> {

  @JsonProperty String version;
  @JsonProperty Instant generatedOn;
  @JsonProperty Result<S, ApiError> result;
}
```

{% endcode %}

Results have different success types, depending on the specific endpoint. Failures will be encapsulated as instances of `ApiError`.

## Controllers

Controllers return instances of `ApiResponse` that will be serialized to JSON by Spring Boot.

{% code title="PetController.java" %}

```java
@RestController
public class PetController {
  // ...
  @GetMapping("/pet")
  ApiResponse<Collection<Pet>> list(@RequestHeader("X-Type") RepositoryType type) {
    log.info("List all pets in {} pet store", type);
    return response(locate(type)
      .flatMapSuccess(PetRepository::listPets)
      .ifSuccess(x -> log.info("Listed {} pet(s) in {}", x.size(), type))
      .ifFailure(this::logError));
  }
}
```

{% endcode %}

Since failures are expressed as `ApiError` objects, endpoints invariably return HTTP status `200`.

## Running the Application

The application can be built and run with Gradle.

```
./gradlew bootRun
```

This will start a stand-alone server on port 8080.

## Testing the Server

Once started, you can interact with the API.

```bash
curl -s -H 'x-type: local' http://localhost:8080/pet/0
```

You should see a JSON response like this:

```json
{
  "version": "1.0",
  "result": {
    "success":{
      "id": 0,
      "name": "Rocky",
      "status": "AVAILABLE"
    }
  }
}
```

## Using Swagger-UI

You can navigate to <http://localhost:8080/> to inspect the API using an interactive UI

![Swagger-UI](https://dev.leakyabstractions.com/result-example-spring-boot/swagger-ui.png)

{% hint style="success" %}
The full source code for the example application is [available on GitHub](https://github.com/LeakyAbstractions/result-example-spring-boot).
{% endhint %}


# Micronaut Demo Project

Take a look at a Micronaut-based REST API leveraging Result objects

This demo project demonstrates how to handle and serialize `Result` objects within a [Micronaut](https://micronaut.io/) application. It provides a working example of a "pet store" web service that exposes a REST API for managing pets.

## Generating the Project

The project was generated via [Micronaut Launch](https://launch.micronaut.io) including features: *annotation-api*, *http-client*, *openapi*, *serialization-jackson*, *swagger-ui*, *toml*, and *validation*.

## Adding Serialization Support

Then [Micronaut Serialization for Result objects](/add-ons/micronaut) was manually added as a dependency to serialize and deserialize `Result` objects.

{% code title="build.gradle" %}

```groovy
dependencies {
    // ...
    implementation(platform("com.leakyabstractions:result-bom:1.0.0.0"))
    implementation("com.leakyabstractions:result")
    implementation("com.leakyabstractions:result-micronaut-serde")
}
```

{% endcode %}

That's all we need to do to make Micronaut treat results as [`Serdeable`](https://javadoc.io/doc/io.micronaut.serde/micronaut-serde-api/latest/io/micronaut/serde/annotation/Serdeable.html).

## API Responses

API responses contain a `Result` field, encapsulating the outcome of the requested operation.

{% code title="ApiResponse.java" %}

```java
@Serdeable
public class ApiResponse<S> {

  @JsonProperty String version;
  @JsonProperty Instant generatedOn;
  @JsonProperty Result<S, ApiError> result;
}
```

{% endcode %}

Results have different success types, depending on the specific endpoint. Failures will be encapsulated as instances of `ApiError`.

## Controllers

Controllers return instances of `ApiResponse` that will be serialized to JSON by Micronaut:

{% code title="PetController.java" %}

```java
@Controller
public class PetController {
  // ...
  @Get("/pet")
  ApiResponse<Collection<Pet>> list(@Header("X-Type") RepositoryType type) {
    log.info("List all pets in {} pet store", type);
    return response(locate(type)
        .flatMapSuccess(PetRepository::listPets)
        .ifSuccess(x -> log.info("Listed {} pet(s) in {}", x.size(), type))
        .ifFailure(this::logError));
  }
}
```

{% endcode %}

Since failures are expressed as `ApiError` objects, endpoints invariably return HTTP status `200`.

## Running the Application

The application can be built and run with Gradle.

```
./gradlew run
```

This will start a stand-alone server on port 8080.

## Testing the Server

Once started, you can interact with the API.

```bash
curl -s -H 'x-type: local' http://localhost:8080/pet/0
```

You should see a JSON response like this:

```json
{
  "version": "1.0",
  "result": {
    "success":{
      "id": 0,
      "name": "Rocky",
      "status": "AVAILABLE"
    }
  }
}
```

## Using Swagger-UI

You can navigate to <http://localhost:8080/> to inspect the API using an interactive UI.

![Swagger-UI](https://dev.leakyabstractions.com/result-example-micronaut/swagger-ui.png)

{% hint style="success" %}
The full source code for the example application is [available on GitHub](https://github.com/LeakyAbstractions/result-example-micronaut).
{% endhint %}


# License

Feel free to tweak and share — no strings attached

This library is licensed under the *Apache License, Version 2.0* (the "License"); you may not use it except in compliance with the License.

You may obtain a copy of the License at <https://www.apache.org/licenses/LICENSE-2.0>

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, **WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND**, either express or implied.

See the License for the specific language governing permissions and limitations under the License.

{% hint style="success" %}
**Permitted**

* **Commercial Use**: You may use this library and derivatives for commercial purposes.
* **Modification**: You may modify this library.
* **Distribution**: You may distribute this library.
* **Patent Use**: This license provides an express grant of patent rights from contributors.
* **Private Use**: You may use and modify this library without distributing it.
  {% endhint %}

{% hint style="info" %}
**Required**

* **License and Copyright Notice**: If you distribute this library you must include a copy of the license and copyright notice.
* **State Changes**: If you modify and distribute this library you must document changes made to this library.
  {% endhint %}

{% hint style="warning" %}
**Forbidden**

* **Trademark use**: This license does not grant any trademark rights.
* **Liability**: The library author cannot be held liable for damages.
* **Warranty**: This library is provided without any warranty.
  {% endhint %}


