Either.java
// Generated by delombok at Mon Nov 18 07:27:48 UTC 2024
package de.larssh.utils;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Function;
import edu.umd.cs.findbugs.annotations.Nullable;
/**
* A container object which contains a value matching either one or another type
* represented by {@code <A>} and {@code <B>}.
*
* <p>
* The value can be accessed in a type-safe way using {@link #getFirst()} and
* {@link #getSecond()}.
*
* <p>
* Additional methods to process the value based on its type and resulting in a
* fixed typed instance are provided, such as {@link #map(Function, Function)}.
*
* <p>
* This is a <a href="../lang/doc-files/ValueBased.html">value-based</a> class;
* use of identity-sensitive operations (including reference equality
* ({@code ==}), identity hash code, or synchronization) on instances of
* {@code Optional} may have unpredictable results and should be avoided.
*
* @param <A> first type of value
* @param <B> second type of value
*/
public class Either<A, B> {
/**
* Returns an {@link Either} object describing the given value. One of both
* parameters has to be non null (means being set), the other one has to be null
* (means being not set).
*
* @param <A> type of first value
* @param <B> type of second value
* @param first value of first type or {@code null}
* @param second value of second type or {@code null}
* @return an {@link Either} object with the given value
* @throws NullPointerException if both parameters are {@code null}
* @throws IllegalArgumentException if both parameters are non-{@code null}
* @deprecated This is a convenience method for special cases only. Use
* {@link #ofFirst} and {@link #ofSecond} where possible.
*/
@Deprecated
@SuppressWarnings({"PMD.AvoidThrowingNullPointerException", "PMD.ShortMethodName"})
public static <A, B> Either<A, B> of(@Nullable final A first, @Nullable final B second) {
if (first == null && second == null) {
throw new NullPointerException();
}
if (first != null && second != null) {
throw new IllegalArgumentException("Two values given while expecting exactly one value.");
}
return new Either<>(Optional.ofNullable(first), Optional.ofNullable(second));
}
/**
* Returns an {@link Either} object describing the given value of the
* <b>first</b> type.
*
* @param <A> first type of value
* @param <B> second type of value
* @param value value to describe
* @return an {@link Either} object describing the given value
*/
public static <A, B> Either<A, B> ofFirst(final A value) {
return new Either<>(Optional.of(value), Optional.empty());
}
/**
* Returns an {@link Either} object describing the given value of the
* <b>second</b> type.
*
* @param <A> first type of value
* @param <B> second type of value
* @param value value to describe
* @return an {@link Either} object describing the given value
*/
public static <A, B> Either<A, B> ofSecond(final B value) {
return new Either<>(Optional.empty(), Optional.of(value));
}
/**
* Value of first type
*/
private final Optional<A> first;
/**
* Value of second type
*/
private final Optional<B> second;
/**
* Invoke either consumer depending on which value is present..
*
* @param firstConsumer block to be executed if the first value is present
* @param secondConsumer block to be executed if the second value is present
*/
public void ifPresent(final Consumer<? super A> firstConsumer, final Consumer<? super B> secondConsumer) {
ifFirstIsPresent(firstConsumer);
ifSecondIsPresent(secondConsumer);
}
/**
* If the first value is present, invoke the specified consumer with the value,
* otherwise do nothing.
*
* @param consumer block to be executed if the first value is present
*/
public void ifFirstIsPresent(final Consumer<? super A> consumer) {
first.ifPresent(consumer);
}
/**
* If the second value is present, invoke the specified consumer with the value,
* otherwise do nothing.
*
* @param consumer block to be executed if the second value is present
*/
public void ifSecondIsPresent(final Consumer<? super B> consumer) {
second.ifPresent(consumer);
}
/**
* If value is of first type {@code functionA} is applied, else value is of
* second type and {@code functionB} is applied. The resulting value is
* returned.
*
* <p>
* <b>Example:</b> The first type is somehow used for user input, while the
* second one is used for system default values.
*
* <pre>
* Either<String, Number> either = Either.ofFirst("123");
*
* String text = either.map(s -> "Changed", n -> "System default");
* long value = either.map(Long::parseLong, Number::longValue);
* </pre>
*
* @param <T> resulting type
* @param firstFunction function to map value, if it is of first type
* @param secondFunction function to map value, if it is of second type
* @return result after mapping the value using either {@code functionA} or
* {@code functionB}
*/
@Nullable
public <T> T map(final Function<? super A, ? extends T> firstFunction, final Function<? super B, ? extends T> secondFunction) {
if (first.isPresent()) {
return first.map(firstFunction).orElseThrow(IllegalStateException::new);
}
return second.map(secondFunction).orElseThrow(IllegalStateException::new);
}
/**
* If the value is of second type {@code function} is applied and the resulting
* value is returned else the value is of first type and returned as-is.
*
* <p>
* <b>Example:</b> The first type is somehow used for user input, while the
* second one is used for system default values.
*
* <pre>
* Either<String, Number> either = Either.ofFirst("123");
*
* String text = either.map(s -> "Changed", n -> "System default");
* Number value = either.mapFirst(Long::parseLong);
* </pre>
*
* @param function function to map value, if it is of first type
* @return value if it is of second type, else result after mapping it using
* {@code function}
*/
@Nullable
public B mapFirst(final Function<? super A, ? extends B> function) {
return second.orElseGet(() -> first.map(function).orElseThrow(IllegalStateException::new));
}
/**
* If the value is of first type {@code function} is applied and the resulting
* value is returned else the value is of second type and returned as-is.
*
* <p>
* <b>Example:</b> The first type is somehow used for user input, while the
* second one is used for system default values.
*
* <pre>
* Either<String, Number> either = Either.ofFirst(123);
*
* String text = either.map(s -> "Changed", n -> "System default");
* String displayValue = either.mapSecond(Number::toString);
* </pre>
*
* @param function function to map value, if it is of second type
* @return value if it is of first type, else result after mapping it using
* {@code function}
*/
@Nullable
public A mapSecond(final Function<? super B, ? extends A> function) {
return first.orElseGet(() -> second.map(function).orElseThrow(IllegalStateException::new));
}
/**
* Value of first type
*
* @return value of first type
*/
@java.lang.SuppressWarnings("all")
@edu.umd.cs.findbugs.annotations.SuppressFBWarnings(justification = "generated code")
@lombok.Generated
public Optional<A> getFirst() {
return this.first;
}
/**
* Value of second type
*
* @return value of second type
*/
@java.lang.SuppressWarnings("all")
@edu.umd.cs.findbugs.annotations.SuppressFBWarnings(justification = "generated code")
@lombok.Generated
public Optional<B> getSecond() {
return this.second;
}
@edu.umd.cs.findbugs.annotations.NonNull
@java.lang.Override
@java.lang.SuppressWarnings("all")
@edu.umd.cs.findbugs.annotations.SuppressFBWarnings(justification = "generated code")
@lombok.Generated
public java.lang.String toString() {
return "Either(first=" + this.getFirst() + ", second=" + this.getSecond() + ")";
}
@java.lang.Override
@java.lang.SuppressWarnings("all")
@edu.umd.cs.findbugs.annotations.SuppressFBWarnings(justification = "generated code")
@lombok.Generated
public boolean equals(@edu.umd.cs.findbugs.annotations.Nullable final java.lang.Object o) {
if (o == this) return true;
if (!(o instanceof Either)) return false;
final Either<?, ?> other = (Either<?, ?>) o;
if (!other.canEqual((java.lang.Object) this)) return false;
final java.lang.Object this$first = this.getFirst();
final java.lang.Object other$first = other.getFirst();
if (this$first == null ? other$first != null : !this$first.equals(other$first)) return false;
final java.lang.Object this$second = this.getSecond();
final java.lang.Object other$second = other.getSecond();
if (this$second == null ? other$second != null : !this$second.equals(other$second)) return false;
return true;
}
@java.lang.SuppressWarnings("all")
@edu.umd.cs.findbugs.annotations.SuppressFBWarnings(justification = "generated code")
@lombok.Generated
protected boolean canEqual(@edu.umd.cs.findbugs.annotations.Nullable final java.lang.Object other) {
return other instanceof Either;
}
@java.lang.Override
@java.lang.SuppressWarnings("all")
@edu.umd.cs.findbugs.annotations.SuppressFBWarnings(justification = "generated code")
@lombok.Generated
public int hashCode() {
final int PRIME = 59;
int result = 1;
final java.lang.Object $first = this.getFirst();
result = result * PRIME + ($first == null ? 43 : $first.hashCode());
final java.lang.Object $second = this.getSecond();
result = result * PRIME + ($second == null ? 43 : $second.hashCode());
return result;
}
/**
* Creates a new {@code Either} instance.
*
* @param first Value of first type
* @param second Value of second type
*/
@java.lang.SuppressWarnings("all")
@edu.umd.cs.findbugs.annotations.SuppressFBWarnings(justification = "generated code")
@lombok.Generated
public Either(final Optional<A> first, final Optional<B> second) {
this.first = first;
this.second = second;
}
}