ProjectAres/Util/core/src/main/java/tc/oc/commons/core/util/Optionals.java

171 lines
6.2 KiB
Java

package tc.oc.commons.core.util;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.Optional;
import java.util.Set;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.annotation.Nullable;
import com.google.common.reflect.TypeParameter;
import com.google.common.reflect.TypeToken;
import com.google.inject.TypeLiteral;
import tc.oc.commons.core.reflect.Methods;
import tc.oc.commons.core.reflect.Types;
public final class Optionals {
private Optionals() {}
public static boolean equals(Optional<?> a, Optional<?> b) {
return a.isPresent() && b.isPresent() && a.get().equals(b.get());
}
public static boolean equals(Optional<?> a, Object b) {
return a.isPresent() && a.get().equals(b);
}
public static boolean equals(Object a, Optional<?> b) {
return equals(b, a);
}
public static boolean isInstance(Optional<?> value, Class<?> type) {
return value.isPresent() && type.isInstance(value.get());
}
public static <T> Optional<T> cast(Optional<? super T> value, Class<T> type) {
return isInstance(value, type) ? (Optional<T>) value : Optional.empty();
}
public static <T> Optional<T> cast(@Nullable Object obj, Class<T> type) {
return type.isInstance(obj) ? Optional.ofNullable((T) obj)
: Optional.empty();
}
public static <T> Optional<T> getIf(boolean condition, Supplier<T> supplier) {
return condition ? Optional.of(supplier.get())
: Optional.empty();
}
public static <T, E extends Throwable> Optional<T> ofThrows(Class<E> exception, ThrowingSupplier<T, E> supplier) {
try {
return Optional.of(supplier.getThrows());
} catch(Throwable e) {
if(exception.isInstance(e)) {
return Optional.empty();
}
throw (RuntimeException) e;
}
}
public static <T> Optional<T> filter(T value, Predicate<? super T> filter) {
return Optional.of(value).filter(filter);
}
public static boolean contains(Optional<?> container, Object value) {
return container.isPresent() && container.get().equals(value);
}
public static <T> Set<T> toSet(Optional<T> t) {
return t.isPresent() ? Collections.singleton(t.get())
: Collections.emptySet();
}
public static <T> Stream<T> stream(Optional<T> t) {
return t.map(Stream::of).orElse(Stream.empty());
}
public static <T> Set<T> union(Stream<Optional<? extends T>> optionals) {
return optionals.filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toSet());
}
public static <T> Set<T> union(Collection<Optional<? extends T>> optionals) {
return union(optionals.stream());
}
public static <T> Set<T> union(Optional<? extends T>... optionals) {
return union(Stream.of(optionals));
}
public static <T> Optional<T> first(Iterable<T> iterable) {
final Iterator<T> iterator = iterable.iterator();
return iterator.hasNext() ? Optional.of(iterator.next()) : Optional.empty();
}
public static <T> Optional<T> first(Stream<Optional<? extends T>> options) {
return (Optional<T>) options.filter(Optional::isPresent)
.findFirst()
.orElse(Optional.empty());
}
public static <T> Optional<T> first(Collection<Optional<? extends T>> options) {
return first(options.stream());
}
public static <T> Optional<T> first(Optional<? extends T>... options) {
return first(Stream.of(options));
}
public static <T> TypeToken<Optional<T>> optionalType(TypeToken<T> type) {
return new TypeToken<Optional<T>>(){}.where(new TypeParameter<T>(){}, type);
}
public static <T> TypeLiteral<Optional<T>> optionalType(TypeLiteral<T> type) {
return Types.toLiteral(optionalType(Types.toToken(type)));
}
public static <T> TypeToken<Optional<? extends T>> optionalSubtypes(TypeToken<T> type) {
return new TypeToken<Optional<? extends T>>(){}.where(new TypeParameter<T>(){}, type);
}
public static <T> TypeLiteral<Optional<? extends T>> optionalSubtypes(TypeLiteral<T> type) {
return Types.toLiteral(optionalSubtypes(Types.toToken(type)));
}
private static final Method GET_METHOD = Methods.method(Optional.class, "get");
public static <T> TypeToken<T> elementType(TypeToken<Optional<T>> optionalType) {
return (TypeToken<T>) optionalType.method(GET_METHOD).getReturnType();
}
public static <T> TypeLiteral<T> elementType(TypeLiteral<Optional<T>> optionalType) {
return (TypeLiteral<T>) optionalType.getReturnType(GET_METHOD);
}
public static <T> TypeToken<T> elementType(Type optionalType) {
return elementType((TypeToken<Optional<T>>) TypeToken.of(optionalType));
}
/**
* If the given {@link Optional} is present, return the result of combining its value
* with the identity value, using the given combiner function. Otherwise, return the
* identity value directly.
*/
public static <T, R> R reduce(R identity, Optional<T> optional, BiFunction<? super R, ? super T, ? extends R> combiner) {
return optional.<R>map(value -> combiner.apply(identity, value))
.orElse(identity);
}
public static <T, U> Optional<Pair<T, U>> both(Optional<T> t, Optional<U> u) {
return mapBoth(t, u, Pair::of);
}
public static <T, U, R> Optional<R> mapBoth(Optional<T> t, Optional<U> u, BiFunction<T, U, R> mapper) {
return flatMapBoth(t, u, mapper.andThen(Optional::of));
}
public static <T, U, R> Optional<R> flatMapBoth(Optional<T> t, Optional<U> u, BiFunction<T, U, Optional<R>> mapper) {
return t.isPresent() && u.isPresent() ? mapper.apply(t.get(), u.get())
: Optional.empty();
}
}