Interface Either<L,R>
- Type Parameters:
L- The left typeR- The right type
- All Known Implementing Classes:
Either.Left,Either.Right
Either.Left or a Either.Right. By convention, right is used for success and
left for error.
Some usage examples:
Either.right(1).get() // => 1
Either.left("an error occurred").getLeft() // => "an error occurred"
A right cannot be left (and vice-versa), so you'll need to check it at runtime:
Either<String, Integer> x = Either.right(1);
if (x.isRight()) { // is true
x.getLeft(); // throws NoSuchElementException
}
Either works great if you have complex logic that needs to be executed under complex conditions.
Consider the following code example, in which both method1 and method2 return Either a Right if
the method was successful, or a Left if the method failed somehow.
method1()
.flatMap(i -> method2(i))
.ifRightOrLeft(
ok -> System.out.println("Both methods were successful"),
error -> System.err.println("Either method1 or method2 failed")
)
In this example, method2 is called if and only if method1 returned a Right (i.e. was successful).
Then to finish, a line is printed to std out or err depending on the successful/failure of the
called methods. Note, that the flatMap can also be used to change the type of the Right value.
Also note that the mapping functions can be chained to further change the resulting values at any
stage of the call chain.-
Nested Class Summary
Nested ClassesModifier and TypeInterfaceDescriptionstatic final recordstatic final recordA left for either a left or right.static final recordA right for either a left or right. -
Method Summary
Modifier and TypeMethodDescriptionReturns a collector forEither<L,R>that collects them intoEither<List<L>,List<R>and favorsEither.LeftoverEither.Right.Returns a collector forEither<L,R>that collects them intoEither<L,List<R>and favorsEither.LeftoverEither.Right.Flatmaps the right value into a new Either, if this is aEither.Right.<T> TMaps the right or left value into a new type using the provided functions, depending on whether this is aEither.LeftorEither.Right.get()Returns the right value, if this is aEither.Right.getLeft()Returns the left value, if this is aEither.Left.Returns the right value, or a default value if this is aEither.Left.voidPerforms the given action with the value if this is aEither.Left, otherwise does nothing.voidPerforms the given action with the value if this is aEither.Right, otherwise does nothing.voidifRightOrLeft(Consumer<R> rightAction, Consumer<L> leftAction) Performs the given right action with the value if this is aEither.Right, otherwise performs the given left action with the value.booleanisLeft()Returns true if this Either is aEither.Left.booleanisRight()Returns true if this Either is aEither.Right.static <L,R> Either <L, R> left(L left) Returns aEither.Leftdescribing the given value.Maps the right value, if this is aEither.Right.Maps the left value, if this is aEither.Left.static <R> Either.EitherOptional<R> ofOptional(Optional<R> right) Convenience method to convert anOptional<R>of R to anEither<?, R>, using an intermediary representation of the Optional in the form ofEither.EitherOptional.static <L,R> Either <L, R> right(R right) Returns aEither.Rightdescribing the given value.Executes the given action with the right value if this is aEither.Right, otherwise does nothing.
-
Method Details
-
right
Returns aEither.Rightdescribing the given value.- Type Parameters:
L- the type of the left valueR- the type of the right value- Parameters:
right- the value to describe- Returns:
- a
Either.Rightof the value
-
left
Returns aEither.Leftdescribing the given value.- Type Parameters:
L- the type of the left valueR- the type of the right value- Parameters:
left- the value to describe- Returns:
- a
Either.Leftof the value
-
ofOptional
Convenience method to convert anOptional<R>of R to anEither<?, R>, using an intermediary representation of the Optional in the form ofEither.EitherOptional.Example:
Either.ofOptional(Optional.of(1)) .orElse("left value") .ifRightOrLeft( right -> System.out.println("If Optional is present, right is the contained value"), left -> System.out.println("If Optional is empty, left is the value provided by orElse") );- Type Parameters:
R- the type of the right value- Parameters:
right- The optional that may contain the right value- Returns:
- An intermediary representation
Either.EitherOptional
-
collector
Returns a collector forEither<L,R>that collects them intoEither<List<L>,List<R>and favorsEither.LeftoverEither.Right.This is commonly used to collect a stream of either objects where a right is considered a success and a left is considered an error. If any error has occurred, we're often only interested in the errors and not in the successes. Otherwise, we'd like to collect all success values.
This collector groups all the lefts into one
Listand all the rights into another. When all elements of the stream have been collected and any lefts were encountered, it outputs a left of the list of encountered left values. Otherwise, it outputs a right of all right values it encountered.Examples:
Stream.of(Either.right(1), Either.right(2), Either.right(3)) .collect(Either.collector()) // => a Right .get(); // => List.of(1,2,3) Stream.of(Either.right(1), Either.left("oops"), Either.right(3)) .collect(Either.collector()) // => a Left .getLeft(); // => List.of("oops")- Type Parameters:
L- the type of the left valuesR- the type of the right values- Returns:
- a collector that favors left over right
-
collectorFoldingLeft
static <L,R> Collector<Either<L,R>, collectorFoldingLeft()Tuple<Optional<L>, List<R>>, Either<L, List<R>>> Returns a collector forEither<L,R>that collects them intoEither<L,List<R>and favorsEither.LeftoverEither.Right. While collecting the rights, it folds the left into the first encountered.This is commonly used to collect a stream of either objects where a right is considered a success and a left is considered an error. If any error has occurred, we're often only interested in the first error and not in the successes. Otherwise, we'd like to collect all success values.
This collector looks for a left while it groups all the rights into one
List. When all elements of the stream have been collected and a left was encountered, it outputs the encountered left. Otherwise, it outputs a right of all right values it encountered.Examples:
* Stream.of(Either.right(1), Either.right(2), Either.right(3)) * .collect(Either.collector()) // => a Right * .get(); // => List.of(1,2,3) * * Stream.of(Either.right(1), Either.left("oops"), Either.left("another oops")) * .collect(Either.collector()) // => a Left * .getLeft(); // => "oops" *- Type Parameters:
L- the type of the left valuesR- the type of the right values- Returns:
- a collector that favors left over right
-
isRight
boolean isRight()Returns true if this Either is aEither.Right.- Returns:
- true if right, false if left
-
isLeft
boolean isLeft()Returns true if this Either is aEither.Left.- Returns:
- true if left, false if right
-
get
R get()Returns the right value, if this is aEither.Right.- Returns:
- the right value
- Throws:
NoSuchElementException- if this is aEither.Left
-
getOrElse
Returns the right value, or a default value if this is aEither.Left.- Parameters:
defaultValue- the default value- Returns:
- the right value, or the default value if this is a
Either.Left
-
getLeft
L getLeft()Returns the left value, if this is aEither.Left.- Returns:
- the left value
- Throws:
NoSuchElementException- if this is aEither.Right
-
map
Maps the right value, if this is aEither.Right.- Type Parameters:
T- the type of the resulting right value- Parameters:
right- the mapping function for the right value- Returns:
- a mapped
Either.Rightor the sameEither.Left
-
mapLeft
Maps the left value, if this is aEither.Left.- Type Parameters:
T- the type of the resulting left value- Parameters:
left- the mapping function for the left value- Returns:
- a mapped
Either.Leftor the sameEither.Right
-
flatMap
Flatmaps the right value into a new Either, if this is aEither.Right.A common use case is to map a right value to a new right, unless some error occurs in which case the value can be mapped to a new left. Note that this flatMap does not allow to alter the type of the left side. Example:
Either.<String, Integer>right(0) // => Right(0) .flatMap(x -> Either.right(x + 1)) // => Right(1) .flatMap(x -> Either.left("an error occurred")) // => Left("an error occurred") .getLeft(); // => "an error occurred"- Type Parameters:
T- the type of the right side of the resulting either- Parameters:
right- the flatmapping function for the right value- Returns:
- either a mapped
Either.Rightor a newEither.Leftif this is a right; otherwise the same left, but cast to consider the new type of the right.
-
thenDo
Executes the given action with the right value if this is aEither.Right, otherwise does nothing. This method facilitates side-effect operations on the right value without altering the state or the type of theEither. After executing the action, the originalEither<L, R>is returned, allowing for further chaining of operations in a fluent API style.When the instance is a
Either.Right, the action is executed, and the originalEither<L, R>is returned. This maintains the right value's type and allows the action to be performed as a side-effect without changing the outcome. When the instance is aEither.Left, no action is performed, and theLeftinstance is returned unchanged, preserving the error information.Usage example when
Eitheris aEither.Right:Either<Exception, String> rightEither = Either.right("Success"); Either<Exception, String> result = rightEither.thenDo(value -> System.out.println("Processed value: " + value)); // Output: Processed value: Success // result remains a Right<Exception, String>, with the value "Success"Usage example when
Eitheris aEither.Left:Either<String, Integer> leftEither = Either.left("Error occurred"); Either<String, Integer> result = leftEither.thenDo(value -> System.out.println("This will not be printed")); // No output as the action is not executed // result remains an unchanged Left<String, Integer>, containing the original error message- Parameters:
action- the consuming function to perform with the right value, if present- Returns:
- Eitherinvalid input: '<'L, R> the original Either instance, allowing further operations.
-
ifRight
Performs the given action with the value if this is aEither.Right, otherwise does nothing.- Parameters:
action- the consuming function for the right value
-
ifLeft
Performs the given action with the value if this is aEither.Left, otherwise does nothing.- Parameters:
action- the consuming function for the left value
-
ifRightOrLeft
Performs the given right action with the value if this is aEither.Right, otherwise performs the given left action with the value.- Parameters:
rightAction- the consuming function for the right valueleftAction- the consuming function for the left value
-
fold
Maps the right or left value into a new type using the provided functions, depending on whether this is aEither.LeftorEither.Right.A common use case is to map to a new common value in success and error cases. Example:
Either<String, Integer> success = Either.right(42); // => Right(42) Either<String, Integer> failure = Either.left("Error occurred"); // => Left("Error occurred") var rightFn = result -> "Success: " + result; var leftFn = error -> "Failure: " + error; success.fold(leftFn, rightFn); // => "Success: 42" failure.fold(leftFn, rightFn); // => "Failure: Error occurred"- Type Parameters:
T- the type of the resulting value- Parameters:
leftFn- the mapping function for the left valuerightFn- the mapping function for the right value- Returns:
- either a mapped
Either.LeftorEither.Right, folded to the new type
-