Jeśli chcesz przetworzyć zaznaczone wyjątki w bezpieczny sposób, potrzebujesz metody pomocniczej, która zapewnia możliwość zawijania wyjątku do podtypu RuntimeException
. Oto taka funkcja pomocnika, który wykorzystuje bezpieczeństwa typu rodzajowego w celu zapewnienia, że tylko zadeklarowane wyjątki zostanie ponownie wyrzucony (chyba, że używasz niebezpiecznej pracy):
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; }
}
Obsługuje dowolną action
który otrzyma funkcję, która robi tymczasowe zawijanie sprawdzanego typu wyjątku do RuntimeException
. To zawijanie będzie przezroczyste, metoda attempt
zakończy normalnie lub wyrzuci oryginalny sprawdzony wyjątek E
(lub niespokrewniony niesprawdzony wyjątek, jeśli wystąpi).
więc można go używać tak:
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); }
}));
}
Ze względu na zagnieżdżonych operacji kompilator nie jest w stanie wywnioskować wyjątek typu automatycznie. Powyższy kod używa wyraźnej deklaracji typu parametru thrower
. Alternatywnie można użyć wywołania typu metody pomocnika, takiej jak
ContainingClass.<SomeCheckedException>attempt(thrower ->
Optional.ofNullable(s).ifPresent(nonNull -> {
try { key(nonNull.get()); }
catch(SomeCheckedException e) { throw thrower.apply(e); }
}));
Ah, nie myślałem, że 'klucz (...)' może rzucić zaznaczony wyjątek. Jednak [moja odpowiedź] (http://stackoverflow.com/a/27900544/2711488) obsługuje również tę sprawę. – Holger