Monad Transformer in Java for handling Asynchronous Operations and errors (Part 2)
Tags: programming, learning, java
Published: 2024-07-04 14:25:45

## Introduction
In the previous [part](https://dev.to/billsoumakis/monad-transformer-in-java-for-handling-asynchronous-operations-and-errors-4hoj) we explained what is a monad, a monad transformer and demonstrated the importance of the `TryT` monad transformer. 
In this part we are going to introduce another monad transformer called `EitherT`.

## What is EitherT

`EitherT` is a monad transformer that encapsulates an `Either` monad inside a `CompletableFuture`.

This combination allows for chaining and composing asynchronous computations that may fail, using functional programming principles. The Either monad represents a value of one of two possible types. Instances of `Either` are either an instance of Left or Right.

* Left is typically used to represent an error or failure.
* Right is used to represent a success or valid result.

By wrapping an `Either` in a `CompletableFuture`, `EitherT` enables the handling of asynchronous operations that can fail or succeed in a functional way.

## Problems solved by `EitherT`

* Error Propagation: Propagates errors through the computation chain without the need for weird error-checking code.
* Composability: Allows for the composition of multiple asynchronous operations, each of which may fail, in an easy to work manner.
* Simplified Error Recovery: Provides straightforward mechanisms to recover from errors.

## Implementation

{% embed https://gist.github.com/VassilisSoum/0ce2425ea35b6e36e26b01054913a894 %}

## Examples

1. Basic usage

```java
import io.vavr.control.Either;

public class EitherTExample {

    public static void main(String[] args) {
        EitherT<String, Integer> successfulComputation = EitherT.right(42);
        EitherT<String, Integer> failedComputation = EitherT.left("Error occurred");

        successfulComputation.getFuture().thenAccept(result ->
            System.out.println("Success: " + result)
        );

        failedComputation.getFuture().thenAccept(result ->
            System.out.println("Failure: " + result)
        );
    }
}
```
In this example, we create two `EitherT` instances: one representing a successful computation and the other a failure. We then use the getFuture() method to access the underlying `CompletableFuture` and handle the results accordingly.

2. Composing Asychronous computations

```java
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;

public class EitherTComposition {

    public static void main(String[] args) {
        EitherT<String, Integer> computation1 = EitherT.right(10);
        EitherT<String, Integer> computation2 = computation1.flatMap(value -> EitherT.right(value * 2));
        EitherT<String, Integer> computation3 = computation2.flatMap(value -> EitherT.right(value + 5));

        computation3.getFuture().thenAccept(result ->
            result.fold(
                error -> System.out.println("Error: " + error),
                value -> System.out.println("Success: " + value)
            )
        );
    }
}
```

3. Error recovery and handling

```java
import java.util.function.Function;

public class EitherTErrorRecovery {

    public static void main(String[] args) {
        EitherT<String, Integer> failedComputation = EitherT.left("Initial error");

        Function<String, EitherT<String, Integer>> recoverFunction = error -> EitherT.right(100);

        EitherT<String, Integer> recoveredComputation = failedComputation.recoverWith(recoverFunction);

        recoveredComputation.getFuture().thenAccept(result ->
            result.fold(
                error -> System.out.println("Error: " + error),
                value -> System.out.println("Recovered Success: " + value)
            )
        );
    }
}
```

## Conclusion

The `EitherT` class is a powerful tool for managing asynchronous computations and error handling in Java and it shows us that it is not hard to embrace functional programming constructs and philosophy in Java.