All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.codemodder.Either Maven / Gradle / Ivy

There is a newer version: 0.98.6
Show newest version
package io.codemodder;

import java.util.Objects;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;

/** An implementation of the Either monad. It holds a single value of two possible types. */
public class Either {

  private final L leftValue;
  private final R rightValue;

  private Either(L left, R right) {
    this.leftValue = left;
    this.rightValue = right;
  }

  /** Returns {@code true} if the left value is present. */
  public boolean isLeft() {
    return leftValue != null;
  }

  /** Returns {@code true} if the right value is present. */
  public boolean isRight() {
    return leftValue == null;
  }

  /** Returns the left value, may be {@code null} */
  public L getLeft() {
    return leftValue;
  }

  /** Returns the right value, may be {@code null} */
  public R getRight() {
    return rightValue;
  }

  /** Returns an {@link Either} containing {@code value} as a left value. */
  public static  Either left(A value) {
    return new Either<>(Objects.requireNonNull(value), null);
  }

  /** Returns an {@link Either} containing {@code value} as a right value. */
  public static  Either right(B value) {
    return new Either<>(null, Objects.requireNonNull(value));
  }

  /** Applies {@code func} to the left value if present. */
  public  Either map(Function func) {
    if (this.isLeft()) return Either.left(func.apply(this.leftValue));
    else return Either.right(this.rightValue);
  }

  /**
   * Applies {@code func} to the right value if present and returns an {@code Either} containing the
   * result. Otherwise, returns an {@code Either} containing the left value.
   */
  public  Either flatMap(Function> func) {
    if (this.isLeft()) {
      var other = func.apply(this.leftValue);
      if (other.isLeft()) return Either.left(other.leftValue);
      else return Either.right(other.rightValue);
    } else return Either.right(this.rightValue);
  }

  /** Applies {@code func} to the left value if present. */
  public  Either mapRight(Function func) {
    if (this.isRight()) return Either.right(func.apply(this.rightValue));
    else return Either.left(this.leftValue);
  }

  /**
   * Applies {@code func} to the right value if present and returns an {@code Either} containing the
   * result. Otherwise, returns an {@code Either} containing the left value.
   */
  public  Either flatMapRight(Function> func) {
    if (this.isRight()) {
      var other = func.apply(this.rightValue);
      if (other.isRight()) return Either.right(other.rightValue);
      else return Either.left(other.leftValue);
    } else return Either.left(this.leftValue);
  }

  /**
   * Builds {@code Either} from an {@link Optional} where either it contains the value of
   * the {@link Optional} or the {@code orElse} object.
   */
  public static  Either fromOptional(Optional maybe, R orElse) {
    return maybe.>map(Either::left).orElseGet(() -> Either.right(orElse));
  }

  /**
   * If it contains the left value, applies the {@link Predicate} {@code pred} and return an {@code
   * Either} containing {@code orElse} if it fails. Otherwise do nothing
   */
  public Either filter(Predicate pred, R orElse) {
    if (this.isLeft()) {
      if (pred.test(this.leftValue)) return this;
      else return Either.right(orElse);
    } else return this;
  }

  /**
   * Applies the {@link Consumer} {@code leftAction} if it contains the left value, or the {@code
   * rightAction} otherwise.
   */
  public void ifLeftOrElse(Consumer leftAction, Consumer rightAction) {
    if (isLeft()) {
      leftAction.accept(getLeft());
    } else {
      rightAction.accept(getRight());
    }
  }

  /** Returns the result of the {@link Function}s {@code leftFunction} or {@code rightFunction}. */
  public  A ifLeftOrElseGet(
      Function leftFunction, Function rightFunction) {
    if (isLeft()) {
      return leftFunction.apply(getLeft());
    } else {
      return rightFunction.apply(getRight());
    }
  }

  @Override
  public String toString() {
    return "Either[" + (this.isLeft() ? this.leftValue : this.rightValue) + "]";
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy