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.97.9
Show newest version
package io.codemodder;

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<>(value, null);
  }

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

  /** Applies {@code func} to the left value if present. */
  public  Either map(Function func) {
    if (this.isLeft()) return new Either<>(func.apply(this.leftValue), null);
    else return new Either<>(null, 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 new Either<>(other.leftValue, null);
      else return new Either<>(null, other.rightValue);
    } else return new Either<>(null, this.rightValue);
  }

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

  /**
   * 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 new Either<>(null, other.rightValue);
      else return new Either<>(other.leftValue, null);
    } else return new Either<>(this.leftValue, null);
  }

  /**
   * 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 - 2024 Weber Informatics LLC | Privacy Policy