(Późno edit:. To pytanie mam nadzieję być nieaktualne gdy Java 7 pochodzi ze względu na "final rethrow" feature który seems like it will be added)Jak bezpieczne jest moje bezpieczne ponowne rzucenie?
Dość często znajdę się w sytuacji wygląda tak:
do some initialization try { do some work } catch any exception { undo initialization rethrow exception }
W języku C# można to zrobić tak:
InitializeStuff();
try
{
DoSomeWork();
}
catch
{
UndoInitialize();
throw;
}
W przypadku języka Java nie ma dobrej zamiany, a od the proposal for improved exception handling was cut from Java 7 wygląda na to, że zajmie to najwyżej kilka lat, dopóki nie otrzymamy czegoś podobnego. Tak więc zdecydowałem się toczyć własne:
(Edit. Pół roku później, final rethrow is back, a przynajmniej tak się wydaje)
public final class Rethrow {
private Rethrow() { throw new AssertionError("uninstantiable"); }
/** Rethrows t if it is an unchecked exception. */
public static void unchecked(Throwable t) {
if (t instanceof Error)
throw (Error) t;
if (t instanceof RuntimeException)
throw (RuntimeException) t;
}
/** Rethrows t if it is an unchecked exception or an instance of E. */
public static <E extends Exception> void instanceOrUnchecked(
Class<E> exceptionClass, Throwable t) throws E, Error,
RuntimeException {
Rethrow.unchecked(t);
if (exceptionClass.isInstance(t))
throw exceptionClass.cast(t);
}
}
Typowe zastosowanie:
public void doStuff() throws SomeException {
initializeStuff();
try {
doSomeWork();
} catch (Throwable t) {
undoInitialize();
Rethrow.instanceOrUnchecked(SomeException.class, t);
// We shouldn't get past the above line as only unchecked or
// SomeException exceptions are thrown in the try block, but
// we don't want to risk swallowing an error, so:
throw new SomeException("Unexpected exception", t);
}
private void doSomeWork() throws SomeException { ... }
}
jest to nieco rozwlekły, łapanie Throwable
jest zwykle mile widziane, nie jestem zadowolony z użycia refleksji tylko po to, by wyrzucić wyjątek, i zawsze czuję się trochę nieswojo pisząc "to się nie wydarzy" komentarze, ale w praktyce to działa ell (lub przynajmniej wydaje się). Zastanawiam się:
- Czy mam jakieś usterki w moich metodach pomocy w rethrow? Jakieś przypadki narożne, które przegapiłem? (Wiem, że
Throwable
mogły zostać spowodowane przez coś tak poważnego, że mojaundoInitialize
zawiedzie, ale to jest OK.)- Czy ktoś już to wymyślił? Spojrzałem na Commons Lang's
ExceptionUtils
, ale to robi inne rzeczy.
- Czy ktoś już to wymyślił? Spojrzałem na Commons Lang's
Edit:
finally
nie jest droid szukam. Interesuje mnie tylko robić rzeczy, gdy zostanie zgłoszony wyjątek.- Tak, wiem łapania
Throwable
jest wielki nie-nie, ale myślę, że to mniejsze zło tutaj w porównaniu do mająca trzy klauzule catch (dlaError
,RuntimeException
iSomeException
, odpowiednio) z identycznym kodem. - Zauważ, że nie próbuję tłumić żadnych błędów - chodzi o to, że wszelkie wyjątki wyrzucone w bloku
try
będą nadal pojawiać się w stosie wywołań, gdy tylko przewinąłem kilka rzeczy.
Masz dobre uzasadnienie dla łowienia Throwable. Nie pozwól, aby cię to zepsuło. To bardzo przypomina użycie GOTO, "Nigdy go nie używaj, chyba że musisz." –