feat(commons): add switchsupport package for using switch instead of try/catch or Optional.*
This commit is contained in:
parent
f66a7b5656
commit
704e1987c4
|
@ -0,0 +1,138 @@
|
|||
package io.gitlab.jfronny.commons.switchsupport;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public sealed interface Opt<T> {
|
||||
record Some<T>(T value) implements Opt<T> {
|
||||
public static <T> Some<T> of(T value) {
|
||||
return new Some<>(value);
|
||||
}
|
||||
}
|
||||
|
||||
record None<T>() implements Opt<T> {
|
||||
public static <T> None<T> of() {
|
||||
return new None<>();
|
||||
}
|
||||
}
|
||||
|
||||
static <T> Opt<T> empty() {
|
||||
return None.of();
|
||||
}
|
||||
|
||||
static <T> Opt<T> of(T value) {
|
||||
return value == null ? None.of() : Some.of(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an Optional to an Opt.
|
||||
* Useful as a static import for switching over Optionals.
|
||||
*
|
||||
* @param optional Optional to convert to Opt
|
||||
* @param <T> Type of the Optional
|
||||
* @return Opt of the Optional
|
||||
*/
|
||||
static <T> Opt<T> over(Optional<T> optional) {
|
||||
return optional.map(Opt::of).orElseGet(Opt::empty);
|
||||
}
|
||||
|
||||
default T get() {
|
||||
return switch (this) {
|
||||
case Some(var value) -> value;
|
||||
case None none -> throw new IllegalStateException("Opt is None");
|
||||
};
|
||||
}
|
||||
|
||||
default T getOrElse(T defaultValue) {
|
||||
return switch (this) {
|
||||
case Some(var value) -> value;
|
||||
case None none -> defaultValue;
|
||||
};
|
||||
}
|
||||
|
||||
default T getOrElseGet(Supplier<T> supplier) {
|
||||
return switch (this) {
|
||||
case Some(var value) -> value;
|
||||
case None none -> supplier.get();
|
||||
};
|
||||
}
|
||||
|
||||
default <X extends Throwable> T getOrElseThrow(Supplier<X> exceptionSupplier) throws X {
|
||||
return switch (this) {
|
||||
case Some(var value) -> value;
|
||||
case None none -> throw exceptionSupplier.get();
|
||||
};
|
||||
}
|
||||
|
||||
default <R> Opt<R> map(Function<T, R> mapper) {
|
||||
return switch (this) {
|
||||
case Some(var value) -> Some.of(mapper.apply(value));
|
||||
case None none -> None.of();
|
||||
};
|
||||
}
|
||||
|
||||
default <R> Opt<R> flatMap(Function<T, Opt<R>> mapper) {
|
||||
return switch (this) {
|
||||
case Some(var value) -> mapper.apply(value);
|
||||
case None none -> None.of();
|
||||
};
|
||||
}
|
||||
|
||||
default void ifPresent(Consumer<T> consumer) {
|
||||
if (this instanceof Some(var value)) consumer.accept(value);
|
||||
}
|
||||
|
||||
default void ifPresentOrElse(Consumer<T> consumer, Runnable runnable) {
|
||||
switch (this) {
|
||||
case Some(var value) -> consumer.accept(value);
|
||||
case None none -> runnable.run();
|
||||
}
|
||||
}
|
||||
|
||||
default Opt<T> filter(Predicate<T> predicate) {
|
||||
return switch (this) {
|
||||
case Some(var value) when predicate.test(value) -> this;
|
||||
case Some some -> None.of();
|
||||
case None none -> this;
|
||||
};
|
||||
}
|
||||
|
||||
default Opt<T> or(Supplier<Opt<T>> supplier) {
|
||||
return switch (this) {
|
||||
case Some some -> this;
|
||||
case None none -> supplier.get();
|
||||
};
|
||||
}
|
||||
|
||||
default Opt<T> orElse(Opt<T> other) {
|
||||
return switch (this) {
|
||||
case Some some -> this;
|
||||
case None none -> other;
|
||||
};
|
||||
}
|
||||
|
||||
default T orElseGet(Supplier<T> supplier) {
|
||||
return switch (this) {
|
||||
case Some(var value) -> value;
|
||||
case None none -> supplier.get();
|
||||
};
|
||||
}
|
||||
|
||||
default <X> Result<T, X> toResult(Supplier<X> errorSupplier) {
|
||||
return switch (this) {
|
||||
case Some(var value) -> Result.success(value);
|
||||
case None none -> Result.failure(errorSupplier.get());
|
||||
};
|
||||
}
|
||||
|
||||
default Stream<T> stream() {
|
||||
return switch (this) {
|
||||
case Some(var value) -> Stream.of(value);
|
||||
case None none -> Stream.empty();
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
package io.gitlab.jfronny.commons.switchsupport;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public sealed interface Result<T, X> {
|
||||
record Success<T, X>(T value) implements Result<T, X> {
|
||||
public static <T, X> Success<T, X> of(T value) {
|
||||
return new Success<>(value);
|
||||
}
|
||||
}
|
||||
|
||||
record Failure<T, X>(X error) implements Result<T, X> {
|
||||
public static <T, X> Failure<T, X> of(X error) {
|
||||
return new Failure<>(error);
|
||||
}
|
||||
}
|
||||
|
||||
static <T, X> Result<T, X> of(Optional<T> value, Supplier<X> errorSupplier) {
|
||||
return of(Opt.of(value), errorSupplier);
|
||||
}
|
||||
|
||||
static <T, X> Result<T, X> of(Opt<T> value, Supplier<X> errorSupplier) {
|
||||
return value.toResult(errorSupplier);
|
||||
}
|
||||
|
||||
default Opt<T> toOpt() {
|
||||
return switch (this) {
|
||||
case Success(var value) -> Opt.of(value);
|
||||
case Failure(var error) -> Opt.empty();
|
||||
};
|
||||
}
|
||||
|
||||
default <Y> Result<Y, X> map(Function<T, Y> mapper) {
|
||||
return switch (this) {
|
||||
case Success(var value) -> Result.success(mapper.apply(value));
|
||||
case Failure(var error) -> Result.failure(error);
|
||||
};
|
||||
}
|
||||
|
||||
static <T, X> Result<T, X> success(T value) {
|
||||
return Success.of(value);
|
||||
}
|
||||
|
||||
static <T, X> Result<T, X> failure(X error) {
|
||||
return Failure.of(error);
|
||||
}
|
||||
|
||||
default T get() {
|
||||
return switch (this) {
|
||||
case Success(var value) -> value;
|
||||
case Failure(Throwable error) -> throw new IllegalStateException("Result is Failure", error);
|
||||
case Failure(var error) -> throw new IllegalStateException("Result is Failure (" + error + ")");
|
||||
};
|
||||
}
|
||||
|
||||
default Throwable getError() {
|
||||
return switch (this) {
|
||||
case Success s -> throw new IllegalStateException("Result is Success");
|
||||
case Failure(Throwable error) -> error;
|
||||
case Failure(var error) -> new IllegalStateException("Result is Failure (" + error + ")");
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
package io.gitlab.jfronny.commons.throwable;
|
||||
|
||||
import io.gitlab.jfronny.commons.switchsupport.Result;
|
||||
import io.gitlab.jfronny.commons.tuple.Tuple;
|
||||
import org.jetbrains.annotations.*;
|
||||
|
||||
|
@ -113,6 +114,19 @@ public interface ThrowingBiFunction<T, U, R, TEx extends Throwable> {
|
|||
};
|
||||
}
|
||||
|
||||
@Contract(value = "_ -> new", pure = true)
|
||||
@ApiStatus.NonExtendable
|
||||
default @NotNull BiFunction<T, U, Result<R, TEx>> toResult(@NotNull Class<TEx> exception) {
|
||||
return (v, u) -> {
|
||||
try {
|
||||
return Result.success(this.apply(v, u));
|
||||
} catch (Throwable e) {
|
||||
if (exception.isAssignableFrom(e.getClass())) return Result.failure((TEx) e);
|
||||
else throw ExceptionWrapper.wrap(e);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides the exception this could throw from the java compiler, effectively making it unchecked.
|
||||
* Wraps the function in a function not marked to throw the checked exception.
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package io.gitlab.jfronny.commons.throwable;
|
||||
|
||||
import io.gitlab.jfronny.commons.switchsupport.Result;
|
||||
import org.jetbrains.annotations.*;
|
||||
|
||||
import java.util.Objects;
|
||||
|
@ -89,6 +90,19 @@ public interface ThrowingFunction<T, R, TEx extends Throwable> {
|
|||
};
|
||||
}
|
||||
|
||||
@Contract(value = "_ -> new", pure = true)
|
||||
@ApiStatus.NonExtendable
|
||||
default @NotNull Function<T, Result<R, TEx>> toResult(@NotNull Class<TEx> exception) {
|
||||
return v -> {
|
||||
try {
|
||||
return Result.success(this.apply(v));
|
||||
} catch (Throwable e) {
|
||||
if (exception.isAssignableFrom(e.getClass())) return Result.failure((TEx) e);
|
||||
else throw ExceptionWrapper.wrap(e);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides the exception this could throw from the java compiler, effectively making it unchecked.
|
||||
* Wraps the function in a function not marked to throw the checked exception.
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package io.gitlab.jfronny.commons.throwable;
|
||||
|
||||
import io.gitlab.jfronny.commons.switchsupport.Result;
|
||||
import org.jetbrains.annotations.*;
|
||||
|
||||
import java.util.Objects;
|
||||
|
@ -76,6 +77,19 @@ public interface ThrowingSupplier<T, TEx extends Throwable> {
|
|||
};
|
||||
}
|
||||
|
||||
@Contract(value = "_ -> new", pure = true)
|
||||
@ApiStatus.NonExtendable
|
||||
default @NotNull Supplier<Result<T, TEx>> toResult(@NotNull Class<TEx> exception) {
|
||||
return () -> {
|
||||
try {
|
||||
return Result.success(this.get());
|
||||
} catch (Throwable e) {
|
||||
if (exception.isAssignableFrom(e.getClass())) return Result.failure((TEx) e);
|
||||
else throw ExceptionWrapper.wrap(e);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides the exception this could throw from the java compiler, effectively making it unchecked.
|
||||
* Wraps the supplier in a supplier not marked to throw the checked exception.
|
||||
|
|
|
@ -9,4 +9,5 @@ module io.gitlab.jfronny.commons {
|
|||
exports io.gitlab.jfronny.commons.ref;
|
||||
exports io.gitlab.jfronny.commons.throwable;
|
||||
exports io.gitlab.jfronny.commons.tuple;
|
||||
exports io.gitlab.jfronny.commons.switchsupport;
|
||||
}
|
Loading…
Reference in New Issue