package tc.oc.commons.core.exception; import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; import javax.inject.Provider; /** * Hack to allow checked exceptions to be propagated through lambdas * * http://stackoverflow.com/questions/27644361/how-can-i-throw-checked-exceptions-from-inside-java-8-streams */ public final class LambdaExceptionUtils { @FunctionalInterface public interface Consumer_WithExceptions<T, E extends Throwable> { void accept(T t) throws E; } @FunctionalInterface public interface BiConsumer_WithExceptions<T, U, E extends Exception> { void accept(T t, U u) throws E; } @FunctionalInterface public interface Function_WithExceptions<T, R, E extends Exception> { R apply(T t) throws E; } @FunctionalInterface public interface Supplier_WithExceptions<T, E extends Exception> { T get() throws E; } @FunctionalInterface public interface Provider_WithExceptions<T, E extends Exception> { T get() throws E; } @FunctionalInterface public interface Runnable_WithExceptions<E extends Exception> { void run() throws E; } @FunctionalInterface public interface Predicate_WithExceptions<T, E extends Exception> { boolean test(T t) throws E; } public static <E extends Exception> Runnable rethrowRunnable(Runnable_WithExceptions<E> runnable) { return () -> { try { runnable.run(); } catch (Exception exception) { throwAsUnchecked(exception); } }; } /** .forEach(rethrowConsumer(name -> System.out.println(Class.forName(name)))); or .forEach(rethrowConsumer(ClassNameUtil::println)); */ public static <T, E extends Throwable> Consumer<T> rethrowConsumer(Consumer_WithExceptions<T, E> consumer) { return t -> { try { consumer.accept(t); } catch (Throwable exception) { throwAsUnchecked(exception); } }; } public static <T, U, E extends Exception> BiConsumer<T, U> rethrowBiConsumer(BiConsumer_WithExceptions<T, U, E> biConsumer) { return (t, u) -> { try { biConsumer.accept(t, u); } catch (Exception exception) { throwAsUnchecked(exception); } }; } /** .map(rethrowFunction(name -> Class.forName(name))) or .map(rethrowFunction(Class::forName)) */ public static <T, R, E extends Exception> Function<T, R> rethrowFunction(Function_WithExceptions<T, R, E> function) { return t -> { try { return function.apply(t); } catch (Exception exception) { throwAsUnchecked(exception); return null; } }; } /** rethrowSupplier(() -> new StringJoiner(new String(new byte[]{77, 97, 114, 107}, "UTF-8"))), */ public static <T, E extends Exception> Supplier<T> rethrowSupplier(Supplier_WithExceptions<T, E> function) { return () -> { try { return function.get(); } catch (Exception exception) { throwAsUnchecked(exception); return null; } }; } public static <T, E extends Exception> Provider<T> rethrowProvider(Provider_WithExceptions<T, E> function) { return () -> { try { return function.get(); } catch (Exception exception) { throwAsUnchecked(exception); return null; } }; } public static <T, E extends Exception> Predicate<T> rethrowPredicate(Predicate_WithExceptions<T, E> predicate) { return t -> { try { return predicate.test(t); } catch (Exception exception) { throwAsUnchecked(exception); return false; } }; } /** uncheck(() -> Class.forName("xxx")); */ public static void uncheck(Runnable_WithExceptions t) { try { t.run(); } catch (Exception exception) { throwAsUnchecked(exception); } } /** uncheck(() -> Class.forName("xxx")); */ public static <R, E extends Exception> R uncheck(Supplier_WithExceptions<R, E> supplier) { try { return supplier.get(); } catch (Exception exception) { throwAsUnchecked(exception); return null; } } /** uncheck(Class::forName, "xxx"); */ public static <T, R, E extends Exception> R uncheck(Function_WithExceptions<T, R, E> function, T t) { try { return function.apply(t); } catch (Exception exception) { throwAsUnchecked(exception); return null; } } @SuppressWarnings ("unchecked") private static <E extends Throwable> void throwAsUnchecked(Throwable exception) throws E { throw (E) exception; } }