DEV Community

Cover image for Monad Transformer in Java for handling Asynchronous Operations and errors (Part 2)
Vasilis Soumakis
Vasilis Soumakis

Posted on

Monad Transformer in Java for handling Asynchronous Operations and errors (Part 2)

Introduction

In the previous part 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

Examples

  1. Basic usage
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)
        );
    }
}
Enter fullscreen mode Exit fullscreen mode

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.

  1. Composing Asychronous computations
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)
            )
        );
    }
}
Enter fullscreen mode Exit fullscreen mode
  1. Error recovery and handling
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)
            )
        );
    }
}
Enter fullscreen mode Exit fullscreen mode

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.

Top comments (0)