Skip to content

Instantly share code, notes, and snippets.

@shawnz
Last active June 21, 2021 16:22
Show Gist options
  • Save shawnz/f5d5f704594e2e9d3cae344fcb77f93f to your computer and use it in GitHub Desktop.
Save shawnz/f5d5f704594e2e9d3cae344fcb77f93f to your computer and use it in GitHub Desktop.
package org.shawnz.util;
import java.util.NoSuchElementException;
import java.util.function.Function;
public abstract class Either<L, R> {
private Either() {
}
public static <L, R> Either<L, R> ofLeft(L left) {
return new Left<>(left);
}
public static <L, R> Either<L, R> ofLeft(L left, Class<R> other) {
return ofLeft(left);
}
public static <L, R> Either<L, R> ofRight(R right) {
return new Right<>(right);
}
public static <L, R> Either<L, R> ofRight(R right, Class<L> other) {
return ofRight(right);
}
public static <L, R, T> Function<Either<L, R>, Either<? extends T, R>> leftMapper(
Function<? super L, ? extends T> leftFunction) {
return either -> either.mapLeft(leftFunction);
}
public static <L, R, T> Function<Either<L, R>, Either<L, ? extends T>> rightMapper(
Function<? super R, ? extends T> rightFunction) {
return either -> either.mapRight(rightFunction);
}
public abstract <T> T map(Function<? super L, ? extends T> leftFunction, Function<? super R, ? extends T> rightFunction);
public <T> Either<T, R> mapLeft(Function<? super L, ? extends T> leftFunction) {
//noinspection unchecked
return map(
left -> ofLeft(leftFunction.apply(left)),
right -> (Either<T, R>) this
);
}
public <T> Either<L, T> mapRight(Function<? super R, ? extends T> rightFunction) {
//noinspection unchecked
return map(
left -> (Either<L, T>) this,
right -> ofRight(rightFunction.apply(right))
);
}
public L getLeft() {
return this.map(Function.identity(), right -> {
throw new NoSuchElementException();
});
}
public R getRight() {
return this.map(left -> {
throw new NoSuchElementException();
}, Function.identity());
}
public boolean hasLeft() {
return this.map(left -> true, right -> false);
}
public boolean hasRight() {
return this.map(left -> false, right -> true);
}
private static final class Left<L, R> extends Either<L, R> {
private final L left;
private Left(L left) {
if (left == null)
throw new NullPointerException();
this.left = left;
}
@Override
public <T> T map(Function<? super L, ? extends T> leftFunction, Function<? super R, ? extends T> rightFunction) {
return leftFunction.apply(left);
}
}
private static final class Right<L, R> extends Either<L, R> {
private final R right;
private Right(R right) {
if (right == null)
throw new NullPointerException();
this.right = right;
}
@Override
public <T> T map(Function<? super L, ? extends T> leftFunction, Function<? super R, ? extends T> rightFunction) {
return rightFunction.apply(right);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment