From 3b1a681088a8ba128acd0e4be0056f8fe4af8f85 Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Tue, 23 Nov 2021 11:03:31 +0100 Subject: [PATCH] Added more functions to Either and make it right-biased --- .../de/tototec/utils/functional/Either.java | 317 ++++++++++-------- 1 file changed, 178 insertions(+), 139 deletions(-) diff --git a/src/main/java/de/tototec/utils/functional/Either.java b/src/main/java/de/tototec/utils/functional/Either.java index 03051a6..c24f9ce 100644 --- a/src/main/java/de/tototec/utils/functional/Either.java +++ b/src/main/java/de/tototec/utils/functional/Either.java @@ -1,153 +1,192 @@ package de.tototec.utils.functional; import java.io.Serializable; +import java.util.Collections; +import java.util.List; import java.util.NoSuchElementException; /** * Value class representing exactly one of two options, left or right. - * + *

* This class is immutable and thus threadsafe. * - * @param - * The type of the left option. - * @param - * The type of the right option. + * @param The type of the left option. + * @param The type of the right option. */ public final class Either implements Serializable { - private static final long serialVersionUID = 1L; - - private final L left; - private final R right; - private final boolean isRight; - - public static Either left(final L left) { - return new Either(left, null, false); - } - - public static Either right(final R right) { - return new Either(null, right, true); - } - - /* package private */ Either(final L left, final R right, final boolean isRight) { - this.left = left; - this.right = right; - this.isRight = isRight; - if (isRight && left != null) { - throw new IllegalArgumentException("Left value must be null"); - } else if (!isRight && right != null) { - throw new IllegalArgumentException("Right value must be null"); - } - } - - public L left() { - if (!isRight) { - return left; - } else { - throw new NoSuchElementException("Left value not defined."); - } - } - - public Optional leftOption() { - if (!isRight) { - return Optional.some(left); - } else { - return Optional.none(); - } - } - - public Try leftTry() { - if (!isRight) { - return Try.success(left); - } else { - return Try.failure(new NoSuchElementException("Either.left.value on Right")); - } - } - - public R right() { - if (isRight) { - return right; - } else { - throw new NoSuchElementException("Right value not defined."); - } - } - - public Optional rightOption() { - if (isRight) { - return Optional.some(right); - } else { - return Optional.none(); - } - } - - public Try rightTry() { - if (isRight) { - return Try.success(right); - } else { - return Try.failure(new NoSuchElementException("Either.right.value on Left")); - } - } - - public boolean isLeft() { - return !isRight; - } - - public boolean isRight() { - return isRight; - } - - @Override - public String toString() { - return isRight ? ("Right(" + right + ")") : ("Left(" + left + ")"); - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + (isRight ? 1231 : 1237); - result = prime * result + ((left == null) ? 0 : left.hashCode()); - result = prime * result + ((right == null) ? 0 : right.hashCode()); - return result; - } - - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final Either other = (Either) obj; - if (isRight != other.isRight) { - return false; - } - if (isRight) { - if (right == null) { - if (other.right != null) { - return false; - } - } else if (!right.equals(other.right)) { - return false; - } - } else { - if (left == null) { - if (other.left != null) { - return false; - } - } else if (!left.equals(other.left)) { - return false; - } - } - return true; - } - - public Either swap() { - return new Either(right, left, !isRight); - } + private static final long serialVersionUID = 1L; + + private final L left; + private final R right; + private final boolean isRight; + + public static Either left(final L left) { + return new Either(left, null, false); + } + + public static Either right(final R right) { + return new Either(null, right, true); + } + + /* package private */ Either(final L left, final R right, final boolean isRight) { + this.left = left; + this.right = right; + this.isRight = isRight; + if (isRight && left != null) { + throw new IllegalArgumentException("Left value must be null"); + } else if (!isRight && right != null) { + throw new IllegalArgumentException("Right value must be null"); + } + } + + public L left() { + if (!isRight) { + return left; + } else { + throw new NoSuchElementException("Left value not defined."); + } + } + + public Optional leftOption() { + if (!isRight) { + return Optional.some(left); + } else { + return Optional.none(); + } + } + + public Try leftTry() { + if (!isRight) { + return Try.success(left); + } else { + return Try.failure(new NoSuchElementException("Either.left.value on Right")); + } + } + + public R right() { + if (isRight) { + return right; + } else { + throw new NoSuchElementException("Right value not defined."); + } + } + + public Optional rightOption() { + if (isRight) { + return Optional.some(right); + } else { + return Optional.none(); + } + } + + public Try rightTry() { + if (isRight) { + return Try.success(right); + } else { + return Try.failure(new NoSuchElementException("Either.right.value on Left")); + } + } + + public boolean isLeft() { + return !isRight; + } + + public boolean isRight() { + return isRight; + } + + @Override + public String toString() { + return isRight ? ("Right(" + right + ")") : ("Left(" + left + ")"); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (isRight ? 1231 : 1237); + result = prime * result + ((left == null) ? 0 : left.hashCode()); + result = prime * result + ((right == null) ? 0 : right.hashCode()); + return result; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final Either other = (Either) obj; + if (isRight != other.isRight) { + return false; + } + if (isRight) { + if (right == null) { + if (other.right != null) { + return false; + } + } else if (!right.equals(other.right)) { + return false; + } + } else { + if (left == null) { + if (other.left != null) { + return false; + } + } else if (!left.equals(other.left)) { + return false; + } + } + return true; + } + + public Either swap() { + return new Either(right, left, !isRight); + } + + public C fold(F1 l, F1 r) { + return isRight ? r.apply(right) : l.apply(left); + } + + public Either map(F1 f) { + return isRight ? Either.right(f.apply(right)) : (Either) left; + } + + public Either flatMap(F1> f) { + return isRight ? f.apply(right) : (Either) left; + } + + public void foreach(final Procedure1 f) { + if (isRight) { + f.apply(right); + } + } + + public R getOrElse(final R t) { + return isRight ? right : t; + } + + public R getOrElseF(final F0 f) { + return isRight ? right : f.apply(); + } + + public Either orElse(Either or) { + return isRight ? this : or; + } + + public Either orElseF(F0> or) { + return isRight ? this : or.apply(); + } + + public List toList() { + return isRight ? Collections.singletonList(right) : Collections.emptyList(); + } + }