Skip to content

Instantly share code, notes, and snippets.

@sviperll
Created October 2, 2018 13:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sviperll/ba5d6cfcde3700db768525041d625812 to your computer and use it in GitHub Desktop.
Save sviperll/ba5d6cfcde3700db768525041d625812 to your computer and use it in GitHub Desktop.
Try (aka Exception-monad) for Java
package com.github.sviperll;
import com.github.sviperll.exception.ExceptionfulConsumer;
import com.github.sviperll.exception.ExceptionfulFunction;
import com.github.sviperll.exception.ExceptionfulRunnable;
import com.github.sviperll.exception.ExceptionfulSupplier;
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Stream;
@ParametersAreNonnullByDefault
public class Try<T, X extends Exception> {
private final ExceptionfulSupplier<T, X> valueSupplier;
public Try(ExceptionfulSupplier<T, X> valueSupplier) {
this.valueSupplier = valueSupplier;
}
public T orElseThrow() throws X {
return valueSupplier.get();
}
public T handleException(Class<X> exceptionClass, Function<X, T> exceptionHandler) {
try {
return orElseThrow();
} catch (Exception ex) {
return handleException(ex, exceptionClass, exceptionHandler);
}
}
public Try<T, X> onException(Class<X> exceptionClass, Function<X, Try<T, X>> exceptionHandler) {
Try<Try<T, X>, X> mapped = this.map(Try::<T, X>of);
return mapped.handleException(exceptionClass, exceptionHandler);
}
public <Y extends Exception> Try<T, Y> mapException(
Class<X> sourceExceptionClass,
Function<X, Y> transformation
) {
Try<Try<T, Y>, X> mapped = this.map(Try::<T, Y>of);
return mapped.handleException(sourceExceptionClass, ex -> Try.exception(transformation.apply(ex)));
}
public <R> Try<R, X> map(Function<T, R> transformation) {
return Try.supplier(() -> transformation.apply(valueSupplier.get()));
}
public <R> Try<R, X> flatMap(Function<T, Try<R, X>> transformation) {
return Try.supplier(() -> transformation.apply(valueSupplier.get()).orElseThrow());
}
public Optional<T> toOptional(Class<X> exceptionClass) {
return this.map(Optional::of).handleException(exceptionClass, ex -> Optional.empty());
}
public static <T, X extends Exception> Try<T, X> supplier(
ExceptionfulSupplier<T, X> valueSupplier
) {
return new Try<>(valueSupplier);
}
public static <T, R, X extends Exception> Function<T, Try<R, X>> function(
ExceptionfulFunction<T, R, X> function
) {
return argument -> supplier(() -> function.apply(argument));
}
public static <T, X extends Exception> Function<T, Try<Unit, X>> consumer(
ExceptionfulConsumer<T, X> consumer
) {
return argument -> supplier(() -> {
consumer.accept(argument);
return Unit.UNIT;
});
}
public static <X extends Exception> Try<Unit, X> runnable(
ExceptionfulRunnable<X> runnable
) {
return supplier(() -> {
runnable.run();
return Unit.UNIT;
});
}
public static <T, X extends Exception> Try<T, X> of(T value) {
return new Try<>(() -> value);
}
public static <T, X extends Exception> Try<T, X> exception(X exception) {
return new Try<>(() -> {
throw exception;
});
}
public static <T, R, X extends Exception> Function<Try<T, X>, Try<R, X>> mapping(
Function<T, R> transformation
) {
return aTry -> aTry.map(transformation);
}
public static <T, R, X extends Exception> Function<Try<T, X>, Try<R, X>> flatMapping(
Function<T, Try<R, X>> transformation
) {
return aTry -> aTry.flatMap(transformation);
}
public static <T, X extends Exception, Y extends Exception> Function<Try<T, X>, Try<T, Y>> mappingException(
Class<X> sourceExceptionClass,
Function<X, Y> transformation
) {
return aTry -> aTry.mapException(sourceExceptionClass, transformation);
}
public static <T, X extends Exception> T handleException(
Exception ex,
Class<X> exceptionClass,
Function<X, T> exceptionHandler
) {
if (exceptionClass.isInstance(ex)) {
return exceptionHandler.apply(exceptionClass.cast(ex));
} else if (ex instanceof RuntimeException) {
throw (RuntimeException) ex;
} else {
throw new IllegalArgumentException(String.format("Unexpected exception: %s", ex));
}
}
public static <T, X extends Exception> Optional<Try<T, X>> intoOptional(
Class<X> exceptionClass,
Try<Optional<T>, X> aTry
) {
return aTry.map(Optionals.mapping(Try::<T, X>of))
.handleException(exceptionClass, ex -> Optional.of(Try.exception(ex)));
}
public static <T, X extends Exception> Stream<Try<T, X>> intoStream(
Class<X> exceptionClass,
Try<Stream<T>, X> aTry
) {
return aTry.map(Streams.mapping(Try::<T, X>of))
.handleException(exceptionClass, ex -> Stream.generate(() -> Try.exception(ex)));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment