Niektórzy próbują cię przekonać, że musisz grać według zasad. Posłuchaj, ale czy jesteś posłuszny, powinieneś zdecydować sam w zależności od sytuacji. Rzeczywistość jest taka, że „POWINIENEŚ grać według zasad” (a nie „MUSISZ grać według zasad”). Pamiętaj tylko, że jeśli nie będziesz postępować zgodnie z zasadami, może to mieć konsekwencje.
Sytuacja dotyczy nie tylko sytuacji Runnable
, ale z Javą 8 również bardzo często w kontekście Strumieni i innych miejsc, w których wprowadzono funkcjonalne interfejsy bez możliwości radzenia sobie z zaznaczonymi wyjątkami. Na przykład Consumer
, Supplier
, Function
, BiFunction
i tak dalej, wszystkie zostały uznane bez urządzeń do czynienia ze sprawdzonych wyjątków.
Więc jakie są sytuacje i opcje? W poniższym tekście Runnable
jest reprezentatywny dla każdego funkcjonalnego interfejsu, który nie deklaruje wyjątków lub deklaruje wyjątki zbyt ograniczone do danego przypadku użycia.
Runnable
Sam się gdzieś zadeklarowałeś i możesz zamienić na Runnable
coś innego.
- Rozważyć wymianę
Runnable
z Callable<Void>
. Zasadniczo to samo, ale można zgłaszać wyjątki; i musi return null
w końcu, co jest łagodną irytacją.
- Rozważ zastąpienie
Runnable
własnym niestandardowym, @FunctionalInterface
który może generować dokładnie te wyjątki, które chcesz.
- Użyłeś interfejsu API i dostępne są alternatywy. Na przykład niektóre interfejsy API języka Java są przeciążone, więc można użyć
Callable<Void>
zamiast Runnable
.
- Użyłeś API i nie ma alternatywy. W takim przypadku nadal nie brakuje Ci opcji.
- Możesz zawinąć wyjątek w
RuntimeException
.
- Możesz zhakować wyjątek do RuntimeException, używając niesprawdzonego rzutowania.
Możesz spróbować następujących rzeczy. To trochę hackowanie, ale czasami potrzebujemy włamania. Ponieważ to, czy wyjątek powinien być zaznaczony, czy odznaczony, jest określane przez jego typ, ale praktycznie powinno być definiowane przez sytuację.
@FunctionalInterface
public interface ThrowingRunnable extends Runnable {
@Override
default void run() {
try {
tryRun();
} catch (final Throwable t) {
throwUnchecked(t);
}
}
private static <E extends RuntimeException> void throwUnchecked(Throwable t) {
throw (E) t;
}
void tryRun() throws Throwable;
}
Wolę to bardziej, new RuntimeException(t)
ponieważ ma krótszy ślad stosu.
Możesz teraz:
executorService.submit((ThrowingRunnable) () -> {throw new Exception()});
Zastrzeżenie: Możliwość wykonywania niesprawdzonych rzutów w ten sposób może w rzeczywistości zostać usunięta w przyszłych wersjach języka Java, gdy informacje o typach ogólnych są przetwarzane nie tylko w czasie kompilacji, ale także w czasie wykonywania.