Skip to content

Instantly share code, notes, and snippets.

@poetix
Created March 11, 2016 12:03
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 poetix/d9ccc0d32fd4fb54722b to your computer and use it in GitHub Desktop.
Save poetix/d9ccc0d32fd4fb54722b to your computer and use it in GitHub Desktop.
import java.util.function.*;
public final class Tunnel<E extends Exception> {
public static <E extends Exception, R> R call(Class<? extends E> exceptionClass, Function<Tunnel<E>, R> f) throws E {
try {
return f.apply(new Tunnel<>());
} catch (TunnelledException e) {
throw exceptionClass.cast(e.getCause());
}
}
public static <E extends Exception, R> void run(Class<? extends E> exceptionClass, Consumer<Tunnel<E>> c) throws E {
try {
c.accept(new Tunnel<>());
} catch (TunnelledException e) {
throw exceptionClass.cast(e.getCause());
}
}
public static final class TunnelledException extends RuntimeException {
public TunnelledException(Throwable cause) {
super(cause);
}
}
public interface TunnellingFunction<I, O, E extends Exception> extends Function<I, O> {
@Override
default O apply(I input) {
try {
return applyThrowing(input);
} catch (Exception e) {
throw new TunnelledException(e);
}
}
O applyThrowing(I input) throws E;
}
public interface TunnellingBiFunction<L, R, O, E extends Exception> extends BiFunction<L, R, O> {
@Override
default O apply(L left, R right) {
try {
return applyThrowing(left, right);
} catch (Exception e) {
throw new TunnelledException(e);
}
}
O applyThrowing(L left, R right) throws E;
}
public interface TunnellingSupplier<O, E extends Exception> extends Supplier<O> {
@Override
default O get() {
try {
return getThrowing();
} catch (Exception e) {
throw new TunnelledException(e);
}
}
O getThrowing() throws E;
}
public interface TunnellingConsumer<I, E extends Exception> extends Consumer<I> {
@Override
default void accept(I input) {
try {
acceptThrowing(input);
} catch (Exception e) {
throw new TunnelledException(e);
}
}
void acceptThrowing(I input) throws E;
}
public interface TunnellingBiConsumer<L, R, E extends Exception> extends BiConsumer<L, R> {
@Override
default void accept(L left, R right) {
try {
acceptThrowing(left, right);
} catch (Exception e) {
throw new TunnelledException(e);
}
}
void acceptThrowing(L left, R right) throws E;
}
public <I, O> Function<I, O> wrap(TunnellingFunction<I, O, ? extends E> f) {
return f;
}
public <L, R, O> BiFunction<L, R, O> wrap(TunnellingBiFunction<L, R, O, ? extends E> f) {
return f;
}
public <O> Supplier<O> wrap(TunnellingSupplier<O, ? extends E> c) {
return c;
}
public <I> Consumer<I> wrap(TunnellingConsumer<I, ? extends E> c) {
return c;
}
public <L, R> BiConsumer<L, R> wrap(TunnellingBiConsumer<L, R, ? extends E> c) {
return c;
}
}
public class TunnelTest {
@Test
public void tunnelWrapsFunctions() throws IOException {
List<Integer> ints = Tunnel.call(IOException.class, tunnel ->
Stream.of(1, 2, 3).map(tunnel.wrap(i -> {
if (i == 0) {
throw new IOException();
}
return i;
})).collect(Collectors.toList()));
}
@Test
public void tunnelWrapsCallables() throws IOException {
Tunnel.run(IOException.class, tunnel ->
Stream.of(1, 2, 3).forEach(tunnel.wrap(i -> {
try {
System.out.println(i);
} catch (Exception e) {
throw new IOException(e);
}
})));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment