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
- 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)
);
}
}
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.
- 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)
)
);
}
}
- 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)
)
);
}
}
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)