Created
February 8, 2014 21:21
-
-
Save datayja/8890556 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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