io.github.cwdesautels.monad.Try Maven / Gradle / Ivy
package io.github.cwdesautels.monad;
import io.github.cwdesautels.function.CheckedFunction;
import io.github.cwdesautels.function.CheckedRunnable;
import io.github.cwdesautels.function.CheckedSupplier;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
/**
* Eager opinionated try monad.
*/
public interface Try {
// Constructors
static Try of(CheckedSupplier supplier) {
Objects.requireNonNull(supplier);
try {
return success(supplier.get());
} catch (Exception e) {
return failure(e);
}
}
static Try ofRunnable(CheckedRunnable runnable) {
Objects.requireNonNull(runnable);
return of(() -> {
runnable.run();
return null;
});
}
static Try success(T value) {
return ImmutableSuccess.builder()
.get(value)
.build();
}
static Try failure(Throwable error) {
return ImmutableFailure.builder()
.cause(error)
.build();
}
// Behaviour
T get();
Throwable getCause();
boolean isSuccess();
boolean isFailure();
// Templates
default Try map(CheckedFunction function) {
Objects.requireNonNull(function);
if (isSuccess()) {
return of(() -> function.apply(get()));
} else {
return failure(getCause());
}
}
default Try flatMap(CheckedFunction> function) {
Objects.requireNonNull(function);
if (isSuccess()) {
return of(() -> function.apply(get()))
.map(Objects::requireNonNull)
.map(Try::get);
} else {
return failure(getCause());
}
}
default T orElse(T other) {
if (isFailure()) {
return other;
} else {
return get();
}
}
default T orElseGet(Supplier other) {
Objects.requireNonNull(other);
if (isFailure()) {
return other.get();
} else {
return get();
}
}
default T orElseThrow(Function mapper) throws X {
Objects.requireNonNull(mapper);
if (isFailure()) {
throw mapper.apply(getCause());
} else {
return get();
}
}
default Try ifSuccess(Consumer consumer) {
Objects.requireNonNull(consumer);
if (isSuccess()) {
consumer.accept(get());
}
return this;
}
default Try ifFailure(Consumer consumer) {
Objects.requireNonNull(consumer);
if (isFailure()) {
consumer.accept(getCause());
}
return this;
}
default Try recover(CheckedFunction function) {
return recoverWhen(t -> true, function);
}
default Try recoverWhen(Predicate predicate, CheckedFunction function) {
Objects.requireNonNull(predicate);
Objects.requireNonNull(function);
if (isSuccess() || !predicate.test(getCause())) {
return this;
} else {
return of(() -> function.apply(getCause()));
}
}
default Try exchange(CheckedFunction> function) {
return exchangeWhen(t -> true, function);
}
default Try exchangeWhen(Predicate predicate, CheckedFunction> function) {
Objects.requireNonNull(predicate);
Objects.requireNonNull(function);
if (isSuccess() || !predicate.test(getCause())) {
return this;
} else {
return of(() -> function.apply(getCause()))
.map(Objects::requireNonNull)
.map(Try::get);
}
}
default Either toEither() {
if (isSuccess()) {
return Either.right(get());
} else {
return Either.left(getCause());
}
}
default Optional toOptional() {
if (isSuccess()) {
return Optional.ofNullable(get());
} else {
return Optional.empty();
}
}
}