If you want to handle checked exceptions in a safe manner, you need a helper method that provides the ability to wrap the exception in a subtype of RuntimeException . Here is a helper function that uses Generics type security to ensure that only declared exceptions are thrown back (unless you are using an unsafe operation):
public static <E extends Throwable> void attempt( Consumer<Function<E,RuntimeException>> action) throws E { final class CarryException extends RuntimeException { final E carried; CarryException(E cause) { super(cause); carried=cause; } } try { action.accept( CarryException::new ); } catch(CarryException ex) { throw ex.carried; } }
It supports an arbitrary action that will receive a function that temporarily packs the checked exception type in a RuntimeException . This package will be transparent, the attempt method will either end normally or throw the original exception E (or an unbound exception if it occurred).
So you can use it as follows:
public static void processIterm(Supplier<Key> s) throws SomeCheckedException { attempt( (Function<SomeCheckedException, RuntimeException> thrower) -> Optional.ofNullable(s).ifPresent(nonNull -> { try { key(nonNull.get()); } // assuming key may throw SomeCheckedException catch(SomeCheckedException e) { throw thrower.apply(e); } })); }
Due to nested operations, the compiler cannot automatically infer the type of exception. The code above uses an explicit declaration of the thrower parameter type. Alternatively, you can use a call like helper method, e.g.
ContainingClass.<SomeCheckedException>attempt( thrower -> Optional.ofNullable(s).ifPresent(nonNull -> { try { key(nonNull.get()); } catch(SomeCheckedException e) { throw thrower.apply(e); } }));
Holger
source share