Interface Either<L,R>

Type Parameters:
L - The left type
R - The right type
All Known Implementing Classes:
Either.Left, Either.Right

public interface Either<L,R>
Represents either a 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.
  • Method Details

    • right

      static <L, R> Either<L,R> right(R right)
      Returns a Either.Right describing the given value.
      Type Parameters:
      L - the type of the left value
      R - the type of the right value
      Parameters:
      right - the value to describe
      Returns:
      a Either.Right of the value
    • left

      static <L, R> Either<L,R> left(L left)
      Returns a Either.Left describing the given value.
      Type Parameters:
      L - the type of the left value
      R - the type of the right value
      Parameters:
      left - the value to describe
      Returns:
      a Either.Left of the value
    • ofOptional

      static <R> Either.EitherOptional<R> ofOptional(Optional<R> right)
      Convenience method to convert an Optional<R> of R to an Either<?, R>, using an intermediary representation of the Optional in the form of Either.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

      static <L, R> Collector<Either<L,R>,Tuple<List<L>,List<R>>,Either<List<L>,List<R>>> collector()
      Returns a collector for Either<L,R> that collects them into Either<List<L>,List<R> and favors Either.Left over Either.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 List and 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 values
      R - the type of the right values
      Returns:
      a collector that favors left over right
    • collectorFoldingLeft

      static <L, R> Collector<Either<L,R>,Tuple<Optional<L>,List<R>>,Either<L,List<R>>> collectorFoldingLeft()
      Returns a collector for Either<L,R> that collects them into Either<L,List<R> and favors Either.Left over Either.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 values
      R - the type of the right values
      Returns:
      a collector that favors left over right
    • isRight

      boolean isRight()
      Returns true if this Either is a Either.Right.
      Returns:
      true if right, false if left
    • isLeft

      boolean isLeft()
      Returns true if this Either is a Either.Left.
      Returns:
      true if left, false if right
    • get

      R get()
      Returns the right value, if this is a Either.Right.
      Returns:
      the right value
      Throws:
      NoSuchElementException - if this is a Either.Left
    • getOrElse

      R getOrElse(R defaultValue)
      Returns the right value, or a default value if this is a Either.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 a Either.Left.
      Returns:
      the left value
      Throws:
      NoSuchElementException - if this is a Either.Right
    • map

      <T> Either<L,T> map(Function<? super R,? extends T> right)
      Maps the right value, if this is a Either.Right.
      Type Parameters:
      T - the type of the resulting right value
      Parameters:
      right - the mapping function for the right value
      Returns:
      a mapped Either.Right or the same Either.Left
    • mapLeft

      <T> Either<T,R> mapLeft(Function<? super L,? extends T> left)
      Maps the left value, if this is a Either.Left.
      Type Parameters:
      T - the type of the resulting left value
      Parameters:
      left - the mapping function for the left value
      Returns:
      a mapped Either.Left or the same Either.Right
    • flatMap

      <T> Either<L,T> flatMap(Function<? super R,? extends Either<L,T>> right)
      Flatmaps the right value into a new Either, if this is a Either.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.Right or a new Either.Left if this is a right; otherwise the same left, but cast to consider the new type of the right.
    • ifRight

      void ifRight(Consumer<R> action)
      Performs the given action with the value if this is a Either.Right, otherwise does nothing.
      Parameters:
      action - the consuming function for the right value
    • ifLeft

      void ifLeft(Consumer<L> action)
      Performs the given action with the value if this is a Either.Left, otherwise does nothing.
      Parameters:
      action - the consuming function for the left value
    • ifRightOrLeft

      void ifRightOrLeft(Consumer<R> rightAction, Consumer<L> leftAction)
      Performs the given right action with the value if this is a Either.Right, otherwise performs the given left action with the value.
      Parameters:
      rightAction - the consuming function for the right value
      leftAction - the consuming function for the left value