This commit is contained in:
Johannes Frohnmeyer 2022-04-28 20:52:32 +02:00
commit da6eaff6e7
Signed by: Johannes
GPG Key ID: E76429612C2929F4
20 changed files with 1441 additions and 0 deletions

39
.gitignore vendored Normal file
View File

@ -0,0 +1,39 @@
.gradle
build/
!gradle/wrapper/gradle-wrapper.jar
!**/src/main/**/build/
!**/src/test/**/build/
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
out/
!**/src/main/**/out/
!**/src/test/**/out/
### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
bin/
!**/src/main/**/bin/
!**/src/test/**/bin/
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
### VS Code ###
.vscode/
### Mac OS ###
.DS_Store

41
.gitlab-ci.yml Normal file
View File

@ -0,0 +1,41 @@
image: gradle:alpine
variables:
GRADLE_OPTS: "-Dorg.gradle.daemon=false"
before_script:
- GRADLE_USER_HOME="$(pwd)/.gradle"
- export GRADLE_USER_HOME
stages:
- build
- test
- deploy
build:
stage: build
script: gradle --build-cache assemble
cache:
key: "$CI_COMMIT_REF_NAME"
policy: push
paths:
- build
- .gradle
test:
stage: test
script: gradle check
cache:
key: "$CI_COMMIT_REF_NAME"
policy: pull
paths:
- build
- .gradle
deploy:
only:
refs:
- master
stage: deploy
script:
- gradle --build-cache publish -Pmaven="$CI_API_V4_URL/projects/$CI_PROJECT_ID/packages/maven"

52
build.gradle Normal file
View File

@ -0,0 +1,52 @@
plugins {
id 'java-library'
id 'maven-publish'
}
repositories {
mavenCentral()
}
dependencies {
compileOnly 'org.jetbrains:annotations:23.0.0'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2'
}
test {
useJUnitPlatform()
}
publishing {
publications {
mavenJava(MavenPublication) {
groupId = 'io.gitlab.jfronny'
artifactId = 'commons'
var cl = Calendar.instance
var day = "${cl.get(cl.YEAR)}.${cl.get(cl.MONTH) + 1}.${cl.get(cl.DATE)}"
var time = "${cl.get(cl.HOUR_OF_DAY)}.${cl.get(cl.MINUTE)}.${cl.get(cl.SECOND)}"
version = "0.1.0.$day.$time"
from components.java
}
}
def ENV = System.getenv()
if (project.hasProperty("maven")) {
repositories.maven {
url = project.getProperty("maven")
name = "dynamic"
credentials(HttpHeaderCredentials) {
name = "Job-Token"
value = ENV.CI_JOB_TOKEN
}
authentication {
header(HttpHeaderAuthentication)
}
}
}
repositories.mavenLocal()
}

2
settings.gradle Normal file
View File

@ -0,0 +1,2 @@
rootProject.name = 'Commons'

View File

@ -0,0 +1,53 @@
package io.gitlab.jfronny.commons;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import java.util.Objects;
import java.util.function.Function;
import java.util.function.Supplier;
/**
* A supplier that proxies to a separate supplier and caches its result
*/
public class LazySupplier<T> implements Supplier<T> {
private final Supplier<T> supplier;
private T cache = null;
/**
* Create a lazy supplier from a pre-initialized value.
* The backing supplier will be empty and never called.
* @param value The value to initialize the cache with
*/
public LazySupplier(@NotNull T value) {
this.supplier = () -> {
throw new RuntimeException("Supplier should have never been called");
};
cache = value;
}
/**
* Create a lazy supplier backed with the specified supplier.
* It will at most be called once when this supplier is first used.
* @param supplier The backing supplier
*/
public LazySupplier(@NotNull Supplier<T> supplier) {
this.supplier = Objects.requireNonNull(supplier);
}
@Override @Contract(pure = true) @NotNull public T get() {
if (cache == null) cache = supplier.get();
return cache;
}
/**
* Generates a new lazy supplier from a function.
* This function is provided with this lazy supplier as a data source for transformation.
* Allows complex transformations to not be run if a later supplier has a shortcut
* @param after A backing function for the new lazy supplier
* @return A new lazy supplier
*/
@Contract(pure = true) @NotNull public LazySupplier<T> andThen(@NotNull Function<LazySupplier<T>, T> after) {
return new LazySupplier<>(() -> after.apply(this));
}
}

View File

@ -0,0 +1,117 @@
package io.gitlab.jfronny.commons.throwable;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
/**
* Removes the need for casting when composing throwables
*/
public class Coerce {
/**
* Coerce the java compiler to interpret a lambda as a throwing biConsumer
* @param tr A throwing biConsumer
* @return The throwing biConsumer
*/
@Contract(pure = true) @NotNull
public static <T, U, TEx extends Throwable> ThrowingBiConsumer<T, U, TEx> biConsumer(@NotNull ThrowingBiConsumer<T, U, TEx> tr) {
return tr;
}
/**
* Coerce the java compiler to interpret a lambda as a throwing biFunction
* @param tr A throwing biFunction
* @return The throwing biFunction
*/
@Contract(pure = true) @NotNull
public static <T, U, R, TEx extends Throwable> ThrowingBiFunction<T, U, R, TEx> biFunction(@NotNull ThrowingBiFunction<T, U, R, TEx> tr) {
return tr;
}
/**
* Coerce the java compiler to interpret a lambda as a throwing booleanSupplier
* @param tr A throwing booleanSupplier
* @return The throwing booleanSupplier
*/
@Contract(pure = true) @NotNull
public static <TEx extends Throwable> ThrowingBooleanSupplier<TEx> booleanSupplier(@NotNull ThrowingBooleanSupplier<TEx> tr) {
return tr;
}
/**
* Coerce the java compiler to interpret a lambda as a throwing consumer
* @param tr A throwing consumer
* @return The throwing consumer
*/
@Contract(pure = true) @NotNull
public static <T, TEx extends Throwable> ThrowingConsumer<T, TEx> consumer(@NotNull ThrowingConsumer<T, TEx> tr) {
return tr;
}
/**
* Coerce the java compiler to interpret a lambda as a throwing function
* @param tr A throwing function
* @return The throwing function
*/
@Contract(pure = true) @NotNull
public static <T, R, TEx extends Throwable> ThrowingFunction<T, R, TEx> function(@NotNull ThrowingFunction<T, R, TEx> tr) {
return tr;
}
/**
* Coerce the java compiler to interpret a lambda as a throwing predicate
* @param tr A throwing predicate
* @return The throwing predicate
*/
@Contract(pure = true) @NotNull
public static <T, TEx extends Throwable> ThrowingPredicate<T, TEx> predicate(@NotNull ThrowingPredicate<T, TEx> tr) {
return tr;
}
/**
* Coerce the java compiler to interpret a lambda as a throwing runnable
* @param tr A throwing runnable
* @return The throwing runnable
*/
@Contract(pure = true) @NotNull
public static <TEx extends Throwable> ThrowingRunnable<TEx> runnable(@NotNull ThrowingRunnable<TEx> tr) {
return tr;
}
/**
* Coerce the java compiler to interpret a lambda as a throwing supplier
* @param tr A throwing supplier
* @return The throwing supplier
*/
@Contract(pure = true) @NotNull
public static <T, TEx extends Throwable> ThrowingSupplier<T, TEx> supplier(@NotNull ThrowingSupplier<T, TEx> tr) {
return tr;
}
/**
* Example:
* {@code interface Test<T> {
* T get();
* void consume(T t);
* }
* class Example {
* Test<?> instance;
* void function() {
* Coerce.pin(instance.get(), v -> instance.consume(v)); // This can compile
* instance.consume(instance.get()); // This cannot
* }
* }}
* @param value The value to pin
* @param func The function to apply to the pinned value
* @param <TIn> The type of the value to pin
* @param <TOut> The return type of the function
* @param <TEx> An exception type (if needed)
* @return The result of the function
* @throws TEx If the function throws, nothing is handled here
*/
public static <TIn, TOut, TEx extends Throwable> TOut pin(@Nullable TIn value, @NotNull ThrowingFunction<TIn, TOut, TEx> func) throws TEx {
return Objects.requireNonNull(func).apply(value);
}
}

View File

@ -0,0 +1,101 @@
package io.gitlab.jfronny.commons.throwable;
import io.gitlab.jfronny.commons.tuple.Tuple;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import java.util.Objects;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
@FunctionalInterface
public interface ThrowingBiConsumer<T, U, TEx extends Throwable> {
void accept(T var1, U var2) throws TEx;
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default ThrowingConsumer<Tuple<T, U>, TEx> fromTuple() {
return (t) -> this.accept(t.left(), t.right());
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default <V> ThrowingConsumer<V, ? super TEx> compose(@NotNull ThrowingFunction<? super V, ? extends T, ? extends TEx> left, @NotNull ThrowingFunction<? super V, ? extends U, ? extends TEx> right) {
Objects.requireNonNull(left);
Objects.requireNonNull(right);
return (t) -> this.accept(left.apply(t), right.apply(t));
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default <V, W> ThrowingBiConsumer<V, W, TEx> biCompose(@NotNull ThrowingFunction<? super V, ? extends T, ? extends TEx> left, @NotNull ThrowingFunction<? super W, ? extends U, ? extends TEx> right) {
Objects.requireNonNull(left);
Objects.requireNonNull(right);
return (l, r) -> this.accept(left.apply(l), right.apply(r));
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default <V> ThrowingBiConsumer<V, U, TEx> composeLeft(@NotNull ThrowingFunction<? super V, ? extends T, ? extends TEx> before) {
Objects.requireNonNull(before);
return (l, r) -> this.accept(before.apply(l), r);
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default <V> ThrowingBiConsumer<T, V, TEx> composeRight(@NotNull ThrowingFunction<? super V, ? extends U, ? extends TEx> before) {
Objects.requireNonNull(before);
return (l, r) -> this.accept(l, before.apply(r));
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default ThrowingBiConsumer<T, U, TEx> andThen(@NotNull ThrowingBiConsumer<? super T, ? super U, ? extends TEx> after) {
Objects.requireNonNull(after);
return (l, r) -> {
this.accept(l, r);
after.accept(l, r);
};
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default ThrowingBiConsumer<T, U, TEx> andThen(@NotNull ThrowingRunnable<? extends TEx> after) {
Objects.requireNonNull(after);
return (l, r) -> {
this.accept(l, r);
after.run();
};
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default BiConsumer<T, U> addHandler(@NotNull Consumer<Throwable> handler) {
Objects.requireNonNull(handler);
return (l, r) -> {
try {
this.accept(l, r);
} catch (Throwable e) {
handler.accept(e);
}
};
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default BiConsumer<T, U> addHandler(@NotNull Class<TEx> exception, @NotNull Consumer<TEx> handler) {
Objects.requireNonNull(handler);
return (l, r) -> {
try {
this.accept(l, r);
} catch (Throwable e) {
if (exception.isAssignableFrom(e.getClass()))
handler.accept((TEx) e);
else throw Try.runtimeException(e);
}
};
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default BiConsumer<T, U> orThrow() {
return (l, r) -> {
try {
this.accept(l, r);
} catch (Throwable e) {
throw Try.runtimeException(e);
}
};
}
}

View File

@ -0,0 +1,95 @@
package io.gitlab.jfronny.commons.throwable;
import io.gitlab.jfronny.commons.tuple.Tuple;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import java.util.Objects;
import java.util.function.BiFunction;
import java.util.function.Function;
@FunctionalInterface
public interface ThrowingBiFunction<T, U, R, TEx extends Throwable> {
R apply(T var1, U var2) throws TEx;
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default ThrowingFunction<Tuple<T, U>, R, TEx> fromTuple() {
return (t) -> this.apply(t.left(), t.right());
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default <V> ThrowingFunction<V, R, TEx> compose(@NotNull ThrowingFunction<? super V, ? extends T, ? extends TEx> left, @NotNull ThrowingFunction<? super V, ? extends U, ? extends TEx> right) {
Objects.requireNonNull(left);
Objects.requireNonNull(right);
return (t) -> this.apply(left.apply(t), right.apply(t));
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default <V, W> ThrowingBiFunction<V, W, R, TEx> biCompose(@NotNull ThrowingFunction<? super V, ? extends T, ? extends TEx> left, @NotNull ThrowingFunction<? super W, ? extends U, ? extends TEx> right) {
Objects.requireNonNull(left);
Objects.requireNonNull(right);
return (l, r) -> this.apply(left.apply(l), right.apply(r));
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default <V> ThrowingBiFunction<V, U, R, TEx> composeLeft(@NotNull ThrowingFunction<? super V, ? extends T, ? extends TEx> before) {
Objects.requireNonNull(before);
return (l, r) -> this.apply(before.apply(l), r);
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default <V> ThrowingBiFunction<T, V, R, TEx> composeRight(@NotNull ThrowingFunction<? super V, ? extends U, ? extends TEx> before) {
Objects.requireNonNull(before);
return (l, r) -> this.apply(l, before.apply(r));
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default <V> ThrowingBiFunction<T, U, V, TEx> andThen(@NotNull ThrowingFunction<? super R, ? extends V, ? extends TEx> after) {
Objects.requireNonNull(after);
return (t, u) -> after.apply(this.apply(t, u));
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default ThrowingBiConsumer<T, U, TEx> andThen(@NotNull ThrowingConsumer<? super R, ? extends TEx> after) {
Objects.requireNonNull(after);
return (t, u) -> after.accept(this.apply(t, u));
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default BiFunction<T, U, R> addHandler(@NotNull Function<Throwable, ? extends R> handler) {
Objects.requireNonNull(handler);
return (t, u) -> {
try {
return this.apply(t, u);
} catch (Throwable e) {
return handler.apply(e);
}
};
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default BiFunction<T, U, R> addHandler(@NotNull Class<TEx> exception, @NotNull Function<TEx, ? extends R> handler) {
Objects.requireNonNull(handler);
return (t, u) -> {
try {
return this.apply(t, u);
} catch (Throwable e) {
if (exception.isAssignableFrom(e.getClass()))
return handler.apply((TEx) e);
else throw Try.runtimeException(e);
}
};
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default BiFunction<T, U, R> orThrow() {
return (t, u) -> {
try {
return this.apply(t, u);
} catch (Throwable e) {
throw Try.runtimeException(e);
}
};
}
}

View File

@ -0,0 +1,97 @@
package io.gitlab.jfronny.commons.throwable;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import java.util.Objects;
import java.util.function.BooleanSupplier;
import java.util.function.Predicate;
@FunctionalInterface
public interface ThrowingBooleanSupplier<TEx extends Throwable> {
boolean get() throws TEx;
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default <T> ThrowingPredicate<T, TEx> and(@NotNull ThrowingPredicate<? super T, ? extends TEx> other) {
Objects.requireNonNull(other);
return (t) -> this.get() && other.test(t);
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default ThrowingBooleanSupplier<TEx> and(@NotNull ThrowingBooleanSupplier<? extends TEx> other) {
Objects.requireNonNull(other);
return () -> this.get() && other.get();
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default <T> ThrowingPredicate<T, TEx> or(@NotNull ThrowingPredicate<? super T, ? extends TEx> other) {
Objects.requireNonNull(other);
return (t) -> this.get() || other.test(t);
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default ThrowingBooleanSupplier<TEx> or(@NotNull ThrowingBooleanSupplier<? extends TEx> other) {
Objects.requireNonNull(other);
return () -> this.get() || other.get();
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default <T> ThrowingPredicate<T, TEx> xor(@NotNull ThrowingPredicate<? super T, ? extends TEx> other) {
Objects.requireNonNull(other);
return (t) -> this.get() ^ other.test(t);
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default ThrowingBooleanSupplier<TEx> xor(@NotNull ThrowingBooleanSupplier<? extends TEx> other) {
Objects.requireNonNull(other);
return () -> this.get() ^ other.get();
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default ThrowingBooleanSupplier<TEx> negate() {
return () -> !this.get();
}
@Contract(pure = true) @NotNull
static <TEx extends Throwable> ThrowingBooleanSupplier<TEx> not(@NotNull ThrowingBooleanSupplier<TEx> target) {
return Objects.requireNonNull(target).negate();
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default BooleanSupplier addHandler(@NotNull Predicate<Throwable> handler) {
Objects.requireNonNull(handler);
return () -> {
try {
return this.get();
} catch (Throwable e) {
return handler.test(e);
}
};
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default BooleanSupplier addHandler(@NotNull Class<TEx> exception, @NotNull Predicate<TEx> handler) {
Objects.requireNonNull(handler);
return () -> {
try {
return this.get();
} catch (Throwable e) {
if (exception.isAssignableFrom(e.getClass()))
return handler.test((TEx) e);
else throw Try.runtimeException(e);
}
};
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default BooleanSupplier orThrow() {
return () -> {
try {
return this.get();
} catch (Throwable e) {
throw Try.runtimeException(e);
}
};
}
}

View File

@ -0,0 +1,89 @@
package io.gitlab.jfronny.commons.throwable;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import java.util.Objects;
import java.util.function.Consumer;
@FunctionalInterface
public interface ThrowingConsumer<T, TEx extends Throwable> {
void accept(T var1) throws TEx;
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default <V> ThrowingConsumer<V, TEx> compose(@NotNull ThrowingFunction<? super V, ? extends T, ? extends TEx> before) {
Objects.requireNonNull(before);
return (t) -> this.accept(before.apply(t));
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default ThrowingRunnable<TEx> compose(@NotNull ThrowingSupplier<? extends T, ? extends TEx> before) {
Objects.requireNonNull(before);
return () -> this.accept(before.get());
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default ThrowingConsumer<T, TEx> andThen(@NotNull ThrowingConsumer<? super T, ? extends TEx> after) {
Objects.requireNonNull(after);
return (t) -> {
this.accept(t);
after.accept(t);
};
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default ThrowingConsumer<T, TEx> andThen(@NotNull ThrowingRunnable<? extends TEx> after) {
Objects.requireNonNull(after);
return (t) -> {
this.accept(t);
after.run();
};
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default <V> ThrowingBiConsumer<T, V, TEx> compound(@NotNull ThrowingConsumer<? super V, ? extends TEx> other) {
Objects.requireNonNull(other);
return (l, r) -> {
this.accept(l);
other.accept(r);
};
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default Consumer<T> addHandler(@NotNull Consumer<Throwable> handler) {
Objects.requireNonNull(handler);
return (t) -> {
try {
this.accept(t);
} catch (Throwable e) {
handler.accept(e);
}
};
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default Consumer<T> addHandler(@NotNull Class<TEx> exception, @NotNull Consumer<TEx> handler) {
Objects.requireNonNull(handler);
return (t) -> {
try {
this.accept(t);
} catch (Throwable e) {
if (exception.isAssignableFrom(e.getClass()))
handler.accept((TEx) e);
else throw Try.runtimeException(e);
}
};
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default Consumer<T> orThrow() {
return (t) -> {
try {
this.accept(t);
} catch (Throwable e) {
throw Try.runtimeException(e);
}
};
}
}

View File

@ -0,0 +1,74 @@
package io.gitlab.jfronny.commons.throwable;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import java.util.Objects;
import java.util.function.Function;
@FunctionalInterface
public interface ThrowingFunction<T, R, TEx extends Throwable> {
R apply(T var1) throws TEx;
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default ThrowingSupplier<R, TEx> compose(@NotNull ThrowingSupplier<? extends T, ? extends TEx> before) {
Objects.requireNonNull(before);
return () -> this.apply(before.get());
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default <V> ThrowingFunction<V, R, TEx> compose(@NotNull ThrowingFunction<? super V, ? extends T, ? extends TEx> before) {
Objects.requireNonNull(before);
return (v) -> this.apply(before.apply(v));
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default <V> ThrowingFunction<T, V, TEx> andThen(@NotNull ThrowingFunction<? super R, ? extends V, ? extends TEx> after) {
Objects.requireNonNull(after);
return (t) -> after.apply(this.apply(t));
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default ThrowingConsumer<T, TEx> andThen(@NotNull ThrowingConsumer<? super R, ? extends TEx> after) {
Objects.requireNonNull(after);
return (t) -> after.accept(this.apply(t));
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default Function<T, R> addHandler(@NotNull Function<Throwable, ? extends R> handler) {
Objects.requireNonNull(handler);
return (t) -> {
try {
return this.apply(t);
} catch (Throwable e) {
return handler.apply(e);
}
};
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default Function<T, R> addHandler(@NotNull Class<TEx> exception, Function<TEx, ? extends R> handler) {
Objects.requireNonNull(handler);
return (t) -> {
try {
return this.apply(t);
} catch (Throwable e) {
if (exception.isAssignableFrom(e.getClass()))
return handler.apply((TEx) e);
else throw Try.runtimeException(e);
}
};
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default Function<T, R> orThrow() {
return (t) -> {
try {
return this.apply(t);
} catch (Throwable e) {
throw Try.runtimeException(e);
}
};
}
}

View File

@ -0,0 +1,114 @@
package io.gitlab.jfronny.commons.throwable;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
import java.util.function.Predicate;
@FunctionalInterface
public interface ThrowingPredicate<T, TEx extends Throwable> {
boolean test(T var1) throws TEx;
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default <V> ThrowingPredicate<V, TEx> compose(@NotNull ThrowingFunction<? super V, ? extends T, ? extends TEx> before) {
Objects.requireNonNull(before);
return (t) -> this.test(before.apply(t));
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default ThrowingBooleanSupplier<TEx> compose(@NotNull ThrowingSupplier<? extends T, ? extends TEx> before) {
Objects.requireNonNull(before);
return () -> this.test(before.get());
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default ThrowingPredicate<T, TEx> and(@NotNull ThrowingPredicate<? super T, ? extends TEx> other) {
Objects.requireNonNull(other);
return (t) -> this.test(t) && other.test(t);
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default ThrowingPredicate<T, TEx> and(@NotNull ThrowingBooleanSupplier<? extends TEx> other) {
Objects.requireNonNull(other);
return (t) -> this.test(t) && other.get();
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default ThrowingPredicate<T, TEx> or(@NotNull ThrowingPredicate<? super T, ? extends TEx> other) {
Objects.requireNonNull(other);
return (t) -> this.test(t) || other.test(t);
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default ThrowingPredicate<T, TEx> or(@NotNull ThrowingBooleanSupplier<? extends TEx> other) {
Objects.requireNonNull(other);
return (t) -> this.test(t) || other.get();
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default ThrowingPredicate<T, TEx> xor(@NotNull ThrowingPredicate<? super T, ? extends TEx> other) {
Objects.requireNonNull(other);
return (t) -> this.test(t) ^ other.test(t);
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default ThrowingPredicate<T, TEx> xor(@NotNull ThrowingBooleanSupplier<? extends TEx> other) {
Objects.requireNonNull(other);
return (t) -> this.test(t) ^ other.get();
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default ThrowingPredicate<T, TEx> negate() {
return (t) -> !this.test(t);
}
@Contract(pure = true) @NotNull
static <T> ThrowingPredicate<T, Throwable> isEqual(@Nullable Object targetRef) {
return null == targetRef ? Objects::isNull : targetRef::equals;
}
@Contract(pure = true) @NotNull
static <T, TEx extends Throwable> ThrowingPredicate<T, TEx> not(@NotNull ThrowingPredicate<T, TEx> target) {
return Objects.requireNonNull(target).negate();
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default Predicate<T> addHandler(@NotNull Predicate<Throwable> handler) {
Objects.requireNonNull(handler);
return (r) -> {
try {
return this.test(r);
} catch (Throwable e) {
return handler.test(e);
}
};
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default Predicate<T> addHandler(@NotNull Class<TEx> exception, @NotNull Predicate<TEx> handler) {
Objects.requireNonNull(handler);
return (r) -> {
try {
return this.test(r);
} catch (Throwable e) {
if (exception.isAssignableFrom(e.getClass()))
return handler.test((TEx) e);
else throw Try.runtimeException(e);
}
};
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default Predicate<T> orThrow() {
return (r) -> {
try {
return this.test(r);
} catch (Throwable e) {
throw Try.runtimeException(e);
}
};
}
}

View File

@ -0,0 +1,68 @@
package io.gitlab.jfronny.commons.throwable;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import java.util.Objects;
import java.util.function.Consumer;
@FunctionalInterface
public interface ThrowingRunnable<TEx extends Throwable> {
void run() throws TEx;
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default ThrowingRunnable<TEx> compose(@NotNull ThrowingRunnable<? extends TEx> before) {
Objects.requireNonNull(before);
return () -> {
before.run();
this.run();
};
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default ThrowingRunnable<TEx> andThen(@NotNull ThrowingRunnable<? extends TEx> after) {
Objects.requireNonNull(after);
return () -> {
this.run();
after.run();
};
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default Runnable addHandler(@NotNull Consumer<Throwable> handler) {
Objects.requireNonNull(handler);
return () -> {
try {
this.run();
} catch (Throwable e) {
handler.accept(e);
}
};
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default Runnable addHandler(@NotNull Class<TEx> exception, @NotNull Consumer<TEx> handler) {
Objects.requireNonNull(handler);
return () -> {
try {
this.run();
} catch (Throwable e) {
if (exception.isAssignableFrom(e.getClass()))
handler.accept((TEx) e);
else throw Try.runtimeException(e);
}
};
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default Runnable orThrow() {
return () -> {
try {
this.run();
} catch (Throwable e) {
throw Try.runtimeException(e);
}
};
}
}

View File

@ -0,0 +1,63 @@
package io.gitlab.jfronny.commons.throwable;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import java.util.Objects;
import java.util.function.Function;
import java.util.function.Supplier;
@FunctionalInterface
public interface ThrowingSupplier<T, TEx extends Throwable> {
T get() throws TEx;
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default <V> ThrowingSupplier<V, TEx> andThen(@NotNull ThrowingFunction<? super T, ? extends V, ? extends TEx> after) {
Objects.requireNonNull(after);
return () -> after.apply(this.get());
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default ThrowingRunnable<TEx> andThen(@NotNull ThrowingConsumer<? super T, ? extends TEx> after) {
Objects.requireNonNull(after);
return () -> after.accept(this.get());
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default Supplier<T> addHandler(@NotNull Function<Throwable, ? extends T> handler) {
Objects.requireNonNull(handler);
return () -> {
try {
return this.get();
} catch (Throwable e) {
return handler.apply(e);
}
};
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default Supplier<T> addHandler(@NotNull Class<TEx> exception, @NotNull Function<TEx, ? extends T> handler) {
Objects.requireNonNull(handler);
return () -> {
try {
return this.get();
} catch (Throwable e) {
if (exception.isAssignableFrom(e.getClass()))
return handler.apply((TEx) e);
else throw Try.runtimeException(e);
}
};
}
@Contract(pure = true) @NotNull @ApiStatus.NonExtendable
default Supplier<T> orThrow() {
return () -> {
try {
return this.get();
} catch (Throwable e) {
throw Try.runtimeException(e);
}
};
}
}

View File

@ -0,0 +1,128 @@
package io.gitlab.jfronny.commons.throwable;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
import java.util.function.*;
/**
* try-catch without the hassle (intended for field declarations or lambdas)
*/
public class Try {
/**
* Run a method or an exception handler
* @param tr The method that should be run
* @param alternative A method to run if tr fails
*/
@Contract(pure = true)
public static void orElse(@NotNull ThrowingRunnable<?> tr, @NotNull Consumer<Throwable> alternative) {
Objects.requireNonNull(tr).addHandler(alternative).run();
}
/**
* Run a method or an exception handler
* @param tr The method that should be run
* @param alternative A method to run if tr fails, should return a default value
*/
@Contract(pure = true) @NotNull
public static <T> T orElse(@NotNull ThrowingSupplier<T, ?> tr, @NotNull Function<Throwable, ? extends T> alternative) {
return Objects.requireNonNull(tr).addHandler(alternative).get();
}
/**
* Run a method or throw a runtime exception (aka just ignore that it might throw something)
* @param tr The method that should be run
*/
@Contract(pure = true)
public static void orThrow(@NotNull ThrowingRunnable<?> tr) {
Objects.requireNonNull(tr).orThrow().run();
}
/**
* Run a method or throw a runtime exception (aka just ignore that it might throw something)
* @param tr The method that should be run
*/
@Contract(pure = true) @NotNull
public static <T> T orThrow(@NotNull ThrowingSupplier<T, ?> tr) {
return Objects.requireNonNull(tr).orThrow().get();
}
/**
* Converts a throwing BiConsumer to a normal one by adding an exception handler
* @param tr The method that should be run
* @param handler A method to run if tr fails
* @return A normal BiConsumer
*/
@Contract(pure = true) @NotNull
public static <T, U> BiConsumer<T, U> handle(@NotNull ThrowingBiConsumer<T, U, ?> tr, @NotNull Consumer<Throwable> handler) {
return Objects.requireNonNull(tr).addHandler(handler);
}
/**
* Converts a throwing BiFunction to a normal one by adding an exception handler
* @param tr The method that should be run
* @param handler A method to run if tr fails, should return a default value
* @return A normal BiFunction
*/
@Contract(pure = true) @NotNull
public static <T, U, R> BiFunction<T, U, R> handle(@NotNull ThrowingBiFunction<T, U, R, ?> tr, @NotNull Function<Throwable, ? extends R> handler) {
return Objects.requireNonNull(tr).addHandler(handler);
}
/**
* Converts a throwing Consumer to a normal one by adding an exception handler
* @param tr The method that should be run
* @param handler A method to run if tr fails
* @return A normal Consumer
*/
@Contract(pure = true) @NotNull
public static <T> Consumer<T> handle(@NotNull ThrowingConsumer<T, ?> tr, @NotNull Consumer<Throwable> handler) {
return Objects.requireNonNull(tr).addHandler(handler);
}
/**
* Converts a throwing Function to a normal one by adding an exception handler
* @param tr The method that should be run
* @param handler A method to run if tr fails, should return a default value
* @return A normal Function
*/
@Contract(pure = true) @NotNull
public static <T, R> Function<T, R> handle(@NotNull ThrowingFunction<T, R, ?> tr, @NotNull Function<Throwable, ? extends R> handler) {
return Objects.requireNonNull(tr).addHandler(handler);
}
/**
* Converts a throwing Runnable to a normal one by adding an exception handler
* @param tr The method that should be run
* @param handler A method to run if tr fails
* @return A normal Runnable
*/
@Contract(pure = true) @NotNull
public static Runnable handle(@NotNull ThrowingRunnable<?> tr, @NotNull Consumer<Throwable> handler) {
return Objects.requireNonNull(tr).addHandler(handler);
}
/**
* Converts a throwing Supplier to a normal one by adding an exception handler
* @param tr The method that should be run
* @param handler A method to run if tr fails, should return a default value
* @return A normal Supplier
*/
@Contract(pure = true) @NotNull
public static <T> Supplier<T> handle(@NotNull ThrowingSupplier<T, ?> tr, @NotNull Function<Throwable, ? extends T> handler) {
return Objects.requireNonNull(tr).addHandler(handler);
}
/**
* Converts any throwable to a RuntimeException (returns it if it is already one)
* @param t A throwable to convert
* @return A runtime exception
*/
@Contract(pure = true) @NotNull
protected static RuntimeException runtimeException(@NotNull Throwable t) {
Objects.requireNonNull(t);
return t instanceof RuntimeException e ? e : new RuntimeException(t);
}
}

View File

@ -0,0 +1,45 @@
package io.gitlab.jfronny.commons.tuple;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
import java.util.function.Function;
public record Quadruple<T1, T2, T3, T4>(@Nullable T1 val1, @Nullable T2 val2, @Nullable T3 val3, @Nullable T4 val4) {
@Contract(pure = true) @NotNull
public static <T1, T2, T3, T4> Quadruple<T1, T2, T3, T4> of(@Nullable T1 val1, @Nullable T2 val2, @Nullable T3 val3, @Nullable T4 val4) {
return new Quadruple<>(val1, val2, val3, val4);
}
@Contract(pure = true) @NotNull
public static <T1, T2, T3, T4> Quadruple<T1, T2, T3, T4> of(@NotNull Tuple<T1, T2> left, @NotNull Tuple<T3, T4> right) {
return new Quadruple<>(left.left(), left.right(), right.left(), right.right());
}
@Contract(pure = true) @NotNull
public Tuple<Tuple<T1, T2>, Tuple<T3, T4>> slice() {
return new Tuple<>(new Tuple<>(val1, val2), new Tuple<>(val3, val4));
}
@Contract(pure = true) @NotNull
public <T> Quadruple<T, T2, T3, T4> map1(@NotNull Function<T1, T> mapper) {
return new Quadruple<>(Objects.requireNonNull(mapper).apply(val1), val2, val3, val4);
}
@Contract(pure = true) @NotNull
public <T> Quadruple<T1, T, T3, T4> map2(@NotNull Function<T2, T> mapper) {
return new Quadruple<>(val1, Objects.requireNonNull(mapper).apply(val2), val3, val4);
}
@Contract(pure = true) @NotNull
public <T> Quadruple<T1, T2, T, T4> map3(@NotNull Function<T3, T> mapper) {
return new Quadruple<>(val1, val2, Objects.requireNonNull(mapper).apply(val3), val4);
}
@Contract(pure = true) @NotNull
public <T> Quadruple<T1, T2, T3, T> map4(@NotNull Function<T4, T> mapper) {
return new Quadruple<>(val1, val2, val3, Objects.requireNonNull(mapper).apply(val4));
}
}

View File

@ -0,0 +1,52 @@
package io.gitlab.jfronny.commons.tuple;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
public record Single<T1>(@Nullable T1 val) {
@Contract(pure = true) @NotNull
public static <T1> Single<T1> of(@Nullable T1 val) {
return new Single<>(val);
}
@Contract(pure = true)
public boolean isNull() {
return val == null;
}
@Contract(pure = true)
public boolean isPresent() {
return val != null;
}
@Contract(pure = true) @NotNull
public Predicate<T1> asEqualsPredicate() {
return val == null ? Objects::isNull : val::equals;
}
@Contract(pure = true) @NotNull
public Predicate<T1> asInstanceEqualsPredicate() {
return v -> v == val;
}
@Contract(pure = true) @NotNull
public Supplier<T1> asSupplier() {
return () -> val;
}
@Contract(pure = true) @NotNull
public <T> Single<T> map(@NotNull Function<T1, T> mapper) {
return new Single<>(Objects.requireNonNull(mapper).apply(val));
}
@Contract(pure = true) @Nullable
public T1 get() {
return val;
}
}

View File

@ -0,0 +1,55 @@
package io.gitlab.jfronny.commons.tuple;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
import java.util.function.Function;
public record Triple<T1, T2, T3>(@Nullable T1 val1, @Nullable T2 val2, @Nullable T3 val3) {
@Contract(pure = true) @NotNull
public static <T1, T2, T3> Triple<T1, T2, T3> of(@Nullable T1 val1, @Nullable T2 val2, @Nullable T3 val3) {
return new Triple<>(val1, val2, val3);
}
@Contract(pure = true) @NotNull
public <T> Triple<T, T2, T3> map1(@NotNull Function<T1, T> mapper) {
return new Triple<>(Objects.requireNonNull(mapper).apply(val1), val2, val3);
}
@Contract(pure = true) @NotNull
public <T> Triple<T1, T, T3> map2(@NotNull Function<T2, T> mapper) {
return new Triple<>(val1, Objects.requireNonNull(mapper).apply(val2), val3);
}
@Contract(pure = true) @NotNull
public <T> Triple<T1, T2, T> map3(@NotNull Function<T3, T> mapper) {
return new Triple<>(val1, val2, Objects.requireNonNull(mapper).apply(val3));
}
@Contract(pure = true) @NotNull
public Triple<T2, T3, T1> lShift() {
return new Triple<>(val2, val3, val1);
}
@Contract(pure = true) @NotNull
public Triple<T3, T1, T2> rShift() {
return new Triple<>(val3, val1, val2);
}
@Contract(pure = true) @NotNull
public Triple<T2, T1, T3> swapL() {
return new Triple<>(val2, val1, val3);
}
@Contract(pure = true) @NotNull
public Triple<T1, T3, T2> swapR() {
return new Triple<>(val1, val3, val2);
}
@Contract(pure = true) @NotNull
public Triple<T3, T2, T1> reverse() {
return new Triple<>(val3, val2, val1);
}
}

View File

@ -0,0 +1,93 @@
package io.gitlab.jfronny.commons.tuple;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.function.Function;
public record Tuple<T1, T2>(@Nullable T1 left, @Nullable T2 right) {
@Contract(pure = true) @NotNull
public static <T1, T2> Tuple<T1, T2> of(@Nullable T1 left, @Nullable T2 right) {
return new Tuple<>(left, right);
}
@Contract(pure = true) @NotNull
public static <T1, T2> Tuple<T1, T2> from(@NotNull Map.Entry<T1, T2> entry) {
Objects.requireNonNull(entry);
return new Tuple<>(entry.getKey(), entry.getValue());
}
@Contract(pure = true) @NotNull
public <T> Tuple<T, T2> mapLeft(@NotNull Function<T1, T> mapper) {
return new Tuple<>(Objects.requireNonNull(mapper).apply(left), right);
}
@Contract(pure = true) @NotNull
public <T> Tuple<T1, T> mapRight(@NotNull Function<T2, T> mapper) {
return new Tuple<>(left, Objects.requireNonNull(mapper).apply(right));
}
@Contract(pure = true) @NotNull
public Tuple<T2, T1> swap() {
return new Tuple<>(right, left);
}
@Contract(pure = true)
public static <T1, T2> Set<Tuple<T1, T2>> from(@NotNull Map<T1, T2> map) {
Objects.requireNonNull(map);
return new AbstractSet<>() {
@Override
public int size() {
return map.size();
}
@Override
public boolean isEmpty() {
return map.isEmpty();
}
@Override
public boolean contains(Object o) {
if (o instanceof Tuple tup) {
if (map.containsKey(tup.left) && map.get(tup.left) == tup.right)
return true;
}
if (map.containsKey(o))
return true;
return false;
}
@NotNull
@Override
public Iterator<Tuple<T1, T2>> iterator() {
return map.entrySet().stream().map(Tuple::from).iterator();
}
@NotNull
@Override
public Object[] toArray() {
return map.entrySet().stream().map(Tuple::from).toArray();
}
@Override
public boolean add(Tuple<T1, T2> t1T2Tuple) {
return map.put(t1T2Tuple.left, t1T2Tuple.right) == null;
}
@Override
public boolean remove(Object o) {
if (o instanceof Tuple t) {
return map.remove(t.left, t.right);
}
return map.remove(o) != null;
}
@Override
public void clear() {
map.clear();
}
};
}
}

View File

@ -0,0 +1,63 @@
package io.gitlab.jfronny.commons.test;
import io.gitlab.jfronny.commons.throwable.ThrowingConsumer;
import io.gitlab.jfronny.commons.throwable.ThrowingSupplier;
import io.gitlab.jfronny.commons.throwable.Try;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import static org.junit.jupiter.api.Assertions.*;
public class ThrowableTest {
private static final String NORMAL = "Hello, World!";
private static final String ALT = "Alt";
@Test
void tryOrElse() {
assertDoesNotThrow(() -> Try.orElse(this::throwNoReturn, this::noop));
assertEquals(ALT, Try.orElse(this::throwReturn, this::alt));
assertDoesNotThrow(() -> Try.orElse(this::noThrowNoReturn, this::fail));
assertEquals(NORMAL, Try.orElse(this::noThrowReturn, this::alt));
}
@Test
void tryOrThrow() {
assertDoesNotThrow(() -> Try.orThrow(this::noThrowNoReturn));
assertThrows(RuntimeException.class, () -> Try.orThrow(this::throwNoReturn));
assertEquals(NORMAL, Try.orThrow(this::noThrowReturn));
assertThrows(RuntimeException.class, () -> Try.orThrow(this::throwReturn));
}
@Test
void tryCompose() {
assertDoesNotThrow(() -> ((ThrowingSupplier<String, IOException>) this::noThrowReturn).andThen(String::toCharArray).andThen(s -> {}).orThrow().run());
assertThrows(RuntimeException.class, () -> ((ThrowingConsumer<char[], IOException>)(s -> {})).compose(String::toCharArray).compose(this::throwReturn).orThrow().run());
}
private <T> void noop(T t) {
}
private String alt(Throwable t) {
return ALT;
}
private <T> void fail(T t) {
throw new RuntimeException();
}
private String throwReturn() throws IOException {
throw new IOException();
}
private void throwNoReturn() throws IOException {
throw new IOException();
}
private String noThrowReturn() throws IOException {
return NORMAL;
}
private void noThrowNoReturn() throws IOException {
}
}