Optionals.java
// Generated by delombok at Mon Nov 18 07:27:48 UTC 2024
package de.larssh.utils;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Optional;
import java.util.OptionalDouble;
import java.util.OptionalInt;
import java.util.OptionalLong;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.function.ToDoubleFunction;
import java.util.function.ToIntFunction;
import java.util.function.ToLongFunction;
import java.util.stream.Stream;
import de.larssh.utils.text.Characters;
import de.larssh.utils.text.Strings;
import edu.umd.cs.findbugs.annotations.Nullable;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
/**
* This class contains helper methods for {@link Optional}.
*/
@SuppressWarnings("PMD.GodClass")
public final class Optionals {
/**
* Creates a {@link Comparator} to compare {@link Optional}s based on the inner
* types {@link Comparable} implementation.
*
* @param <T> optional value type
* @return comparator for optional
*/
public static <T extends Comparable<T>> Comparator<? super Optional<? extends T>> comparator() {
return comparator((first, second) -> {
if (first == null) {
if (second == null) {
return 0;
}
// The integer value MIN_VALUE cannot be negated in the integer range as
// [-MIN_VALUE] is mathematically equal to [MAX_VALUE + 1].
final int compare = second.compareTo(null);
return compare == Integer.MIN_VALUE ? Integer.MAX_VALUE : -compare;
}
return first.compareTo(second);
});
}
/**
* Wraps a {@link Comparator} to allow compare {@link Optional}s.
*
* <p>
* When comparing {@code comparator} is called with the optionals object if
* present or {@code null}. Therefore it needs to handle null values
* appropriately. Use {@link Comparator#nullsFirst(Comparator)} and
* {@link Comparator#nullsLast(Comparator)} if your comparator does not.
*
* @param <T> optional value type
* @param comparator optional value comparator
* @return comparator for optional
*/
public static <T> Comparator<? super Optional<? extends T>> comparator(final Comparator<? super T> comparator) {
return (first, second) -> comparator.compare(Nullables.map(second, optional -> optional.orElse(null)), Nullables.map(second, optional -> optional.orElse(null)));
}
/**
* If a value is present, apply the provided {@link OptionalDouble}-bearing
* mapping function to it, return that result, otherwise return an empty
* {@link OptionalDouble}. This method is similar to
* {@link #mapToDouble(Optional, ToDoubleFunction)}, but the provided mapper is
* one whose result is already an {@code OptionalDouble}, and if invoked,
* {@code flatMapToDouble} does not wrap it with an additional
* {@link OptionalDouble}.
*
* @param <T> element type
* @param optional optional value
* @param mapper a mapping function to apply to the value, if present the
* mapping function
* @return the result of applying an {@link OptionalDouble}-bearing mapping
* function to the value of this {@link OptionalDouble}, if a value is
* present, otherwise an empty {@link OptionalDouble}
*/
public static <T> OptionalDouble flatMapToDouble(final Optional<T> optional, final Function<? super T, OptionalDouble> mapper) {
return optional.isPresent() ? mapper.apply(optional.get()) : OptionalDouble.empty();
}
/**
* If a value is present, apply the provided {@link OptionalInt}-bearing mapping
* function to it, return that result, otherwise return an empty
* {@link OptionalInt}. This method is similar to
* {@link #mapToInt(Optional, ToIntFunction)}, but the provided mapper is one
* whose result is already an {@code OptionalInt}, and if invoked,
* {@code flatMap} does not wrap it with an additional {@link OptionalInt}.
*
* @param <T> element type
* @param optional optional value
* @param mapper a mapping function to apply to the value, if present the
* mapping function
* @return the result of applying an {@link OptionalInt}-bearing mapping
* function to the value of this {@link OptionalInt}, if a value is
* present, otherwise an empty {@link OptionalInt}
*/
public static <T> OptionalInt flatMapToInt(final Optional<T> optional, final Function<? super T, OptionalInt> mapper) {
return optional.isPresent() ? mapper.apply(optional.get()) : OptionalInt.empty();
}
/**
* If a value is present, apply the provided {@link OptionalLong}-bearing
* mapping function to it, return that result, otherwise return an empty
* {@link OptionalLong}. This method is similar to
* {@link #mapToLong(Optional, ToLongFunction)}, but the provided mapper is one
* whose result is already an {@code OptionalLong}, and if invoked,
* {@code flatMapToDouble} does not wrap it with an additional
* {@link OptionalLong}.
*
* @param <T> element type
* @param optional optional value
* @param mapper a mapping function to apply to the value, if present the
* mapping function
* @return the result of applying an {@link OptionalLong}-bearing mapping
* function to the value of this {@link OptionalLong}, if a value is
* present, otherwise an empty {@link OptionalLong}
*/
public static <T> OptionalLong flatMapToLong(final Optional<T> optional, final Function<? super T, OptionalLong> mapper) {
return optional.isPresent() ? mapper.apply(optional.get()) : OptionalLong.empty();
}
/**
* Returns the first present value. Returns empty if no value is present.
*
* @param <T> value type
* @param values any number of optional values to test
* @return the first present value, empty if no value is present
*/
@SafeVarargs
public static <T> Optional<T> getFirst(final Optional<T>... values) {
for (final Optional<T> value : values) {
if (value.isPresent()) {
return value;
}
}
return Optional.empty();
}
/**
* Returns the first present value. Values are created on-demand by calling
* {@code suppliers} one after the other. Returns empty if no value is present.
*
* @param <T> value type
* @param suppliers any number of value suppliers, which values to test,
* evaluated in a lazy manner
* @return the first present value, empty if no value is present
*/
@SafeVarargs
public static <T> Optional<T> getFirst(final Supplier<? extends Optional<T>>... suppliers) {
for (final Supplier<? extends Optional<T>> supplier : suppliers) {
final Optional<T> value = supplier.get();
if (value.isPresent()) {
return value;
}
}
return Optional.empty();
}
/**
* Returns an {@link Optional} describing the first value matching the predicate
* {@code isPresent}. Values are created on-demand by calling {@code suppliers}
* one after the other. Returns an empty {@link Optional} if no element matches.
*
* @param <T> type of the return value
* @param isPresent predicate to match
* @param suppliers any number of value suppliers, which values to test,
* evaluated in a lazy manner
* @return an {@link Optional} describing the first value matching the predicate
* {@code isPresent}, an empty {@link Optional} if no element matches
*/
@SafeVarargs
public static <T> Optional<T> getFirst(final Predicate<? super T> isPresent, final Supplier<? extends T>... suppliers) {
for (final Supplier<? extends T> supplier : suppliers) {
final T value = supplier.get();
if (isPresent.test(value)) {
return Optional.ofNullable(value);
}
}
return Optional.empty();
}
/**
* Returns an {@link Optional} describing the first value matching the predicate
* {@code isPresent}. Returns an empty {@link Optional} if no element matches.
*
* @param <T> type of the return value
* @param isPresent predicate to match
* @param values any number of values to test
* @return an {@link Optional} describing the first value matching the predicate
* {@code isPresent}, an empty {@link Optional} if no element matches
*/
@SafeVarargs
public static <T> Optional<T> getFirstValue(final Predicate<? super T> isPresent, final T... values) {
for (final T value : values) {
if (isPresent.test(value)) {
return Optional.ofNullable(value);
}
}
return Optional.empty();
}
/**
* If a value is present, returns an {@link OptionalDouble} describing the
* result. Otherwise returns an empty {@link OptionalDouble}.
*
* @param optional optional value
* @return an {@link OptionalDouble} describing the value of {@code optional},
* if a value is present, otherwise an empty {@link OptionalDouble}
*/
@SuppressFBWarnings(value = "FII_USE_METHOD_REFERENCE", justification = "Missing ToLongFunction.identity()")
public static OptionalDouble mapToDouble(final Optional<Double> optional) {
return mapToDouble(optional, value -> value);
}
/**
* If a value is present, applies {@code mapper} to {@code optional} and returns
* an {@link OptionalDouble} describing the result. Otherwise returns an empty
* {@link OptionalDouble}.
*
* @param <T> element type
* @param optional optional value
* @param mapper a mapping function to apply to the value, if present
* @return an {@link OptionalDouble} describing the result of applying
* {@code mapper} function to the value of {@code optional}, if a value
* is present, otherwise an empty {@link OptionalDouble}
*/
public static <T> OptionalDouble mapToDouble(final Optional<T> optional, final ToDoubleFunction<? super T> mapper) {
return optional.isPresent() ? OptionalDouble.of(mapper.applyAsDouble(optional.get())) : OptionalDouble.empty();
}
/**
* If a value is present, returns an {@link OptionalInt} describing the result.
* Otherwise returns an empty {@link OptionalInt}.
*
* @param optional optional value
* @return an {@link OptionalInt} describing the value of {@code optional}, if a
* value is present, otherwise an empty {@link OptionalInt}
*/
@SuppressFBWarnings(value = "FII_USE_METHOD_REFERENCE", justification = "Missing ToLongFunction.identity()")
public static OptionalInt mapToInt(final Optional<Integer> optional) {
return mapToInt(optional, value -> value);
}
/**
* If a value is present, applies {@code mapper} to {@code optional} and returns
* an {@link OptionalInt} describing the result. Otherwise returns an empty
* {@link OptionalInt}.
*
* @param <T> element type
* @param optional optional value
* @param mapper a mapping function to apply to the value, if present
* @return an {@link OptionalInt} describing the result of applying
* {@code mapper} function to the value of {@code optional}, if a value
* is present, otherwise an empty {@link OptionalInt}
*/
public static <T> OptionalInt mapToInt(final Optional<T> optional, final ToIntFunction<? super T> mapper) {
return optional.isPresent() ? OptionalInt.of(mapper.applyAsInt(optional.get())) : OptionalInt.empty();
}
/**
* If a value is present, returns an {@link OptionalLong} describing the result.
* Otherwise returns an empty {@link OptionalLong}.
*
* @param optional optional value
* @return an {@link OptionalLong} describing the value of {@code optional}, if
* a value is present, otherwise an empty {@link OptionalLong}
*/
@SuppressFBWarnings(value = "FII_USE_METHOD_REFERENCE", justification = "Missing ToLongFunction.identity()")
public static OptionalLong mapToLong(final Optional<Long> optional) {
return mapToLong(optional, value -> value);
}
/**
* If a value is present, applies {@code mapper} to {@code optional} and returns
* an {@link OptionalLong} describing the result. Otherwise returns an empty
* {@link OptionalLong}.
*
* @param <T> element type
* @param optional optional value
* @param mapper a mapping function to apply to the value, if present
* @return an {@link OptionalLong} describing the result of applying
* {@code mapper} function to the value of {@code optional}, if a value
* is present, otherwise an empty {@link OptionalLong}
*/
public static <T> OptionalLong mapToLong(final Optional<T> optional, final ToLongFunction<? super T> mapper) {
return optional.isPresent() ? OptionalLong.of(mapper.applyAsLong(optional.get())) : OptionalLong.empty();
}
/**
* Returns an {@link Optional} describing the specified value, if non-null and
* non-empty, otherwise returns an empty {@link Optional}. The term <i>empty</i>
* is described by {@code isEmpty}.
*
* @param <T> value type
* @param isEmpty predicate describing the term <i>empty</i>
* @param value the possibly-null-or-empty value to describe
* @return an {@link Optional} with a present value if the specified value is
* non-null and non-empty, otherwise an empty {@link Optional}
*/
public static <T> Optional<T> ofNon(final Predicate<? super T> isEmpty, @Nullable final T value) {
return value == null || isEmpty.test(value) ? Optional.empty() : Optional.of(value);
}
/**
* Returns an {@link Optional} describing the specified string, if non-null and
* non-blank, otherwise returns an empty {@link Optional}.
*
* @param string the possibly-null-or-blank string to describe
* @return an {@link Optional} with a present value if the specified string is
* non-null and non-empty after being trimmed, otherwise an empty
* {@link Optional}
*/
public static Optional<String> ofNonBlank(@Nullable final String string) {
return ofNon(Strings::isBlank, string);
}
/**
* Returns an {@link Optional} describing the specified array, if non-null and
* non-empty, otherwise returns an empty {@link Optional}.
*
* @param <T> array element type
* @param array the possibly-null-or-empty array to describe
* @return an {@link Optional} with a present value if the specified array is
* non-null and non-empty, otherwise an empty {@link Optional}
*/
@SuppressWarnings("PMD.UseVarargs")
@SuppressFBWarnings(value = "UVA_USE_VAR_ARGS", justification = "var args make no sense as their length is constant")
public static <T> Optional<T[]> ofNonEmpty(@Nullable final T[] array) {
return ofNon(a -> a.length == 0, array);
}
/**
* Returns an {@link Optional} describing the specified collection, if non-null
* and non-empty, otherwise returns an empty {@link Optional}.
*
* @param <T> collection and collection element type
* @param collection the possibly-null-or-empty collection to describe
* @return an {@link Optional} with a present value if the specified collection
* is non-null and non-empty, otherwise an empty {@link Optional}
*/
public static <T extends Collection<?>> Optional<T> ofNonEmpty(@Nullable final T collection) {
return ofNon(Collection::isEmpty, collection);
}
/**
* Returns an {@link Optional} describing the specified string, if non-null and
* non-empty, otherwise returns an empty {@link Optional}.
*
* @param string the possibly-null-or-empty string to describe
* @return an {@link Optional} with a present value if the specified string is
* non-null and non-empty, otherwise an empty {@link Optional}
*/
public static Optional<String> ofNonEmpty(@Nullable final String string) {
return ofNon(String::isEmpty, string);
}
/**
* Returns an {@link Optional} describing the specified arrays first element, if
* present, otherwise returns an empty {@link Optional}. Throws a
* {@link TooManyElementsException} if {@code array} contains more than one
* element.
*
* @param <T> array element type
* @param array the array describing the element
* @return an {@link Optional} describing the specified arrays first element, if
* present, otherwise returns an empty {@link Optional}
* @throws TooManyElementsException if {@code array} contains more than one
* element
*/
@SuppressWarnings("PMD.UseVarargs")
@SuppressFBWarnings(value = "UVA_USE_VAR_ARGS", justification = "var args make no sense as their length is constant")
public static <T> Optional<T> ofSingle(final T[] array) {
if (array.length == 0) {
return Optional.empty();
}
if (array.length == 1) {
return Optional.ofNullable(array[0]);
}
throw new TooManyElementsException();
}
/**
* Returns an {@link Optional} describing the specified iterables first element,
* if present, otherwise returns an empty {@link Optional}. Throws a
* {@link TooManyElementsException} if {@code iterable} contains more than one
* element.
*
* @param <T> iterable element type
* @param iterable the iterable describing the element
* @return an {@link Optional} describing the specified iterables first element,
* if present, otherwise returns an empty {@link Optional}
* @throws TooManyElementsException if {@code iterable} contains more than one
* element
*/
public static <T> Optional<T> ofSingle(final Iterable<T> iterable) {
return ofSingle(iterable.iterator());
}
/**
* Returns an {@link Optional} describing the specified iterators first element,
* if present, otherwise returns an empty {@link Optional}. Throws a
* {@link TooManyElementsException} if {@code iterator} contains more than one
* element.
*
* @param <T> iterator element type
* @param iterator the iterator describing the element
* @return an {@link Optional} describing the specified iterators first element,
* if present, otherwise returns an empty {@link Optional}
* @throws TooManyElementsException if {@code iterator} contains more than one
* element
*/
@SuppressWarnings("PMD.PrematureDeclaration")
public static <T> Optional<T> ofSingle(final Iterator<T> iterator) {
if (!iterator.hasNext()) {
return Optional.empty();
}
final Optional<T> optional = Optional.ofNullable(iterator.next());
if (iterator.hasNext()) {
throw new TooManyElementsException();
}
return optional;
}
/**
* Returns an {@link Optional} describing the specified streams first element,
* if present, otherwise returns an empty {@link Optional}. Throws a
* {@link TooManyElementsException} if {@code stream} contains more than one
* element.
*
* <p>
* This is a terminal operation.
*
* @param <T> stream element type
* @param stream the stream describing the element
* @return an {@link Optional} describing the specified streams first element,
* if present, otherwise returns an empty {@link Optional}
* @throws TooManyElementsException if {@code stream} contains more than one
* element
*/
public static <T> Optional<T> ofSingle(final Stream<T> stream) {
return ofSingle(stream.iterator());
}
/**
* Returns an {@link OptionalInt} describing the specified strings first
* character, if present, otherwise returns an empty {@link OptionalInt}. Throws
* a {@link TooManyElementsException} if {@code string} contains more than one
* character, ignoring trailing whitespaces.
*
* <p>
* Whitespace characters are recognized using
* {@link Characters#isAsciiWhitespace(char)}.
*
* @param string the string describing the character
* @return an {@link OptionalInt} describing the specified strings first
* character, if present, otherwise returns an empty {@link OptionalInt}
* @throws TooManyElementsException if {@code string} contains more than one
* character, ignoring trailing whitespaces
*/
public static OptionalInt ofSingle(final CharSequence string) {
final int length = string.length();
if (length == 0) {
return OptionalInt.empty();
}
for (int index = 1; index < length; index += 1) {
if (!Characters.isAsciiWhitespace(string.charAt(index))) {
throw new TooManyElementsException();
}
}
return OptionalInt.of(string.charAt(0));
}
/**
* Returns a stream consisting of present elements.
*
* @param <T> element type
* @param optionals array of optional elements
* @return the new stream
*/
@SafeVarargs
public static <T> Stream<T> stream(final Optional<T>... optionals) {
return Arrays.stream(optionals).filter(Optional::isPresent).map(Optional::get);
}
@java.lang.SuppressWarnings("all")
@edu.umd.cs.findbugs.annotations.SuppressFBWarnings(justification = "generated code")
@lombok.Generated
private Optionals() {
throw new java.lang.UnsupportedOperationException("This is a utility class and cannot be instantiated");
}
}