Skip to content

Instantly share code, notes, and snippets.

@datayja
Created February 8, 2014 21:21
Show Gist options
  • Save datayja/8890556 to your computer and use it in GitHub Desktop.
Save datayja/8890556 to your computer and use it in GitHub Desktop.
package com.coral_lang.lib.std;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
public class Either<A, B> {
private final A left;
private final B right;
private static final Either<?, ?> NEITHER = new Either<>();
private Either() {
left = null;
right = null;
}
public static <A, B> Either<A, B> neither() {
@SuppressWarnings("unchecked")
final Either<A, B> neither = (Either<A, B>) NEITHER;
return neither;
}
private Either(final A leftValue, final B rightValue) {
if (leftValue == null && rightValue == null) {
throw new NullPointerException();
}
left = leftValue;
right = rightValue;
}
public static <A, B> Either<A, B> left(final A leftValue) {
return new Either<>(leftValue, null);
}
public static <A, B> Either<A, B> right(final B rightValue) {
return new Either<>(null, rightValue);
}
public static <A, B> Either<A, B> leftNullable(final A leftValue) {
return leftValue == null ? neither() : left(leftValue);
}
public static <A, B> Either<A, B> rightNullable(final B rightValue) {
return rightValue == null ? neither() : right(rightValue);
}
public A getLeft() {
if (left == null) {
throw new NoSuchElementException("Left value is not present");
}
return left;
}
public B getRight() {
if (right == null) {
throw new NoSuchElementException("Right value is not present");
}
return right;
}
public boolean isLeftPresent() {
return left != null;
}
public boolean isRightPresent() {
return right != null;
}
public boolean isAnyPresent() {
return isLeftPresent() || isRightPresent();
}
public void ifPresent(final Consumer<? super A> leftConsumer, final Consumer<? super B> rightConsumer) {
if (left != null) {
leftConsumer.accept(left);
} else if (right != null) {
rightConsumer.accept(right);
}
}
public void ifLeftPresent(final Consumer<? super A> consumer) {
if (left != null) {
consumer.accept(left);
}
}
public void ifRightPresent(final Consumer<? super B> consumer) {
if (right != null) {
consumer.accept(right);
}
}
public void ifAnyPresent(final Consumer<Either<? super A, ? super B>> consumer) {
if (left != null || right != null) {
consumer.accept(this);
}
}
public <R> R reduce(final Function<Either<? super A, ? super B>, R> function) {
Objects.requireNonNull(function);
return Objects.requireNonNull(function.apply(this));
}
public <R> R reduceLeft(final Function<? super A, R> function) {
Objects.requireNonNull(function);
return Objects.requireNonNull(function.apply(left));
}
public <R> R reduceRight(final Function<? super B, R> function) {
Objects.requireNonNull(function);
return Objects.requireNonNull(function.apply(right));
}
public Either<A, B> filter(final Predicate<Either<? super A, ? super B>> predicate) {
Objects.requireNonNull(predicate);
if (!isAnyPresent()) {
return this;
} else {
return predicate.test(this) ? this : neither();
}
}
public <C, D> Either<C, D> map(final Function<Either<? super A, ? super B>, ? extends Either<C, D>> mapper) {
Objects.requireNonNull(mapper);
if (!isAnyPresent()) {
return neither();
} else {
return mapper.apply(this);
}
}
public <R> Optional<R> map(final Function<? super A, ? extends R> leftMapper, final Function<? super B, ? extends R> rightMapper) {
Objects.requireNonNull(leftMapper);
Objects.requireNonNull(rightMapper);
if (left != null) {
return Optional.ofNullable(leftMapper.apply(left));
} else if (right != null) {
return Optional.ofNullable(rightMapper.apply(right));
} else {
return Optional.empty();
}
}
public <R> Optional<R> mapLeft(final Function<? super A, ? extends R> mapper) {
Objects.requireNonNull(mapper);
if (!isLeftPresent()) {
return Optional.empty();
} else {
return Optional.ofNullable(mapper.apply(left));
}
}
public <R> Optional<R> mapRight(final Function<? super B, ? extends R> mapper) {
Objects.requireNonNull(mapper);
if (!isLeftPresent()) {
return Optional.empty();
} else {
return Optional.ofNullable(mapper.apply(right));
}
}
public <R> Optional<R> flatMap(final Function<? super A, Optional<R>> leftMapper, final Function<? super B, Optional<R>> rightMapper) {
Objects.requireNonNull(leftMapper);
Objects.requireNonNull(rightMapper);
if (left != null) {
return Objects.requireNonNull(leftMapper.apply(left));
} else if (right != null) {
return Objects.requireNonNull(rightMapper.apply(right));
} else {
return Optional.empty();
}
}
public <R> Optional<R> flatMapLeft(final Function<? super A, Optional<R>> mapper) {
Objects.requireNonNull(mapper);
if (!isLeftPresent()) {
return Optional.empty();
} else {
return Objects.requireNonNull(mapper.apply(left));
}
}
public <R> Optional<R> flatMapRight(final Function<? super B, Optional<R>> mapper) {
Objects.requireNonNull(mapper);
if (!isLeftPresent()) {
return Optional.empty();
} else {
return Objects.requireNonNull(mapper.apply(right));
}
}
public Either<A, B> orElse(final Either<A, B> other) {
return isAnyPresent() ? this : other;
}
public Either<A, B> orElseGet(final Supplier<? extends Either<A, B>> other) {
return isAnyPresent() ? this : other.get();
}
public <X extends Throwable> Either<A, B> orElseThrow(final Supplier<? extends X> exceptionSupplier) throws X {
if (isAnyPresent()) {
return this;
} else {
throw exceptionSupplier.get();
}
}
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof Either)) {
return false;
}
final Either<?, ?> other = (Either<?, ?>) obj;
return Objects.equals(left, other.left)
&& Objects.equals(right, other.right);
}
@Override
public int hashCode() {
return Objects.hash(left, right);
}
@Override
public String toString() {
if (left != null) {
return String.format("Either.left[%s]", left);
} else if (right != null) {
return String.format("Either.right[%s]", right);
} else {
return "Either.neither";
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment