2015-08-07 14 views
6

Chcę obsługiwać wyjątki z dwóch różnych typów w różny sposób, a następnie wykonać te same działania dla obu typów wyjątków. Jak to zrobić w Javie?Określone i takie same akcje podczas przechwytywania wielu wyjątków

Poniższy kod pokazuje, co chcę zrobić, ale nie jest to poprawne, ponieważ jeden wyjątek nie może zostać przechwycony dwukrotnie.

Jaka jest prawidłowa składnia tego?

try { 
    // do something... 
} 
catch (ExceptionA e) { 
    // actions for ExceptionA 
} 
catch (ExceptionB e) { 
    // actions for ExceptionB 
} 
catch (ExceptionA | ExceptionB e) { 
    // actions for ExceptionA & ExceptionB 
} 
+0

Stwórz własną niestandardową klasę wyjątku. – ravi

+1

Możesz wstawić kod do funkcji i wywołać funkcje w bloku catch. – Jens

+0

@Jens To nie jest rozwiązanie, po prostu wyładowanie problemu gdzieś indziej ... – insidesin

Odpowiedz

4

Użyj konstruktu catch (ExceptionA | ExceptionB e). Wewnątrz bloku catch najpierw wykonaj sprawdzanie instanceof dla e i oddzielnie obsługuj typy wyjątków. Następnie należy wspólnie obsługiwać oba typy. W ten sposób można zrobić wszystko w jednym catch bloku:

try { 
    // do something... 
} catch (ExceptionA | ExceptionB e) { 
    if (e instanceof ExceptionA) { 
     // handling for ExceptionA 
    } else { 
     // handling for ExceptionB 
    } 
    // common handling for both exception types 
} 
+0

Albo możesz zagnieździć dwa, próbować łapać bloki jeden, który obsługuje dwa oddzielnie drugi, który obsługuje wspólny kawałek. kolejność będzie zależeć od tego, czy rzecz, którą chcesz wykonać w jednym lub drugim, zależy od siebie :). – Rob

+0

@Mick Mnemonic Użyłem twojego rozwiązania, ponieważ jest ono najłatwiejsze do odczytania i jasne. –

1

Jeśli szukasz (ExceptionA | ExceptionB) będzie można złapać albo i uchwyt identycznie, tylko jedna będzie musiała zawieść. Jest to w zasadzie tylko nowy (1.7) stenogram dla wielu warunków Exception. Nie ma czegoś takiego jak catch(ExceptionA && ExceptionB).

Na przykład:

readFile { 
    try { 
     open the file; 
     determine its size; 
     determine its content; 
    } catch (fileOpenFailed) { 
     doSomething; 
    } catch (sizeDeterminationFailed) { 
     doSomething; 
    } catch (contentDeterminationFailed) { 
     doSomething; 
    } 
} 

Jeśli chciał złapać contentDeterminationFailed i sizeDeterminationFailed jako jednolitego exception wtedy chcesz tworzyć własne exception typ, który może być obsługiwany jednoznacznie.

1

Zastosować metodę dla wspólnego kodu.

try { 
    // do something... 
} 
catch (ExceptionA e) { 
    // actions for ExceptionA 
    doCommon(parameters); 
} 
catch (ExceptionB e) { 
    // actions for ExceptionA 
    doCommon(parameters); 
} 

..... 

void doCommon(parameters) { 
    // actions for ExceptionA & ExceptionB 
} 

To zadziała dla większości rzeczy.
Chociaż istnieją pewne wyjątki, takie jak return. Do tego można mieć doCommon zwrot pogoda rozmówca musi wrócić lub nie i używać go jako:

catch (ExceptionA e) { 
    // actions for ExceptionA 
    if (doCommon(parameters)) 
     return; 
} 
catch (ExceptionB e) { 
    // actions for ExceptionA 
    if (doCommon(parameters)) 
     return; 
} 

Rozwiązanie „native Java” nie istnieje. JLS określa (podkreślenie moje):

14.20.1. Wykonywanie próbnego catch

Instrukcja try bez bloku finally jest wykonywana przez wykonanie pierwszego bloku . Następnie istnieje możliwość wyboru:

Jeśli wykonanie bloku try zakończy się normalnie, nie zostanie podjęte dalsze działanie , a instrukcja try zakończy się normalnie.

Jeżeli wykonanie bloku try kończy się nagle z powodu rzutu wartość V, po czym istnieje możliwość wyboru:

Jeśli typ run-time V jest kompatybilny z przypisania (§5.2) A klasa wyjątków catchable dowolnej klauzuli catch instrukcji try, , następnie pierwsza (po lewej) taka klauzula catch została wybrana jako.Wartość V jest przypisany do parametru wybranego klauzuli catch, a Blok tej klauzuli catch jest wykonywany, a następnie istnieje możliwość wyboru:

Jeśli blok kończy się normalnie, wtedy instrukcja try zakończy normalnie .

Jeśli ten blok zakończy się nagle z jakiegokolwiek powodu, to instrukcja wypróbowania kończy się nagle z tego samego powodu.

Jeśli typ run-time V nie jest przyporządkowanie kompatybilny z połów klasy wyjątkiem klauzuli catch w instrukcji try, następnie oświadczenie próba kończy się nagle z powodu rzut z wartości V.

Wykonywany jest tylko pierwszy blok catch. Nie ma sposobu na wykonanie dwóch bloków catch dla tej samej instrukcji try.

+0

Metoda ekstrakcji jest oczywiście rozwiązaniem. Ale jestem zainteresowany, jeśli istnieje natywna konstrukcja try/catch dla niego. –

+1

Nie, nie ma takiej konstrukcji. Zaktualizowałem swoją odpowiedź do odpowiedniej części JLS. –

0

Można przekaż wyjątek i obsługiwać go ponownie:

try { 
    try { 
     // do something 
    } catch(ExceptionA e) { 
     // actions for ExceptionA 
     throw e; 
    } catch(ExceptionB e) { 
     // actions for ExceptionB 
     throw e; 
    } 
} catch(ExceptionA | ExceptionB e) { 
    // Actions for exceptions A or B 
} 

Być może, dla jasności, można byłaby do metod. Zakładam, że wyjątki są sprawdzanymi wyjątkami.

private void doSomethingHelper() throws ExceptionA, ExceptionB { 
    try { 
     // do something 
    } catch(ExceptionA e) { 
     // actions for ExceptionA 
     throw e; 
    } catch(ExceptionB e) { 
     // actions for ExceptionB 
     throw e; 
    } 
} 

public void doSomething() { 
    try { 
     doSomethingHelper(); 
    } catch(ExceptionA | ExceptionB e) { 
     // Actions for exceptions A or B 
    } 
} 
+0

To tylko komplikuje sytuację ... Ostatni połów rozwiązuje problem sam. – insidesin

+0

@insidesin Nie zgadzam się, jest to zagnieżdżony blok try. Wewnętrzny haczyk może obsłużyć wyjątek A lub B osobno, podczas gdy zewnętrzny może obsługiwać ogólny sposób postępowania po tym, jak ten wewnętrzny wyjdzie. – dave

+0

Więc z tej przyczyny obchodzisz się z nim dwa razy? Jeśli naprawdę potrzebujesz, wykonaj 'instanceof' .. – insidesin

1

Czy rozwiązaniem tego dzieła typu dla Ciebie:

try { 
// do something... 
} catch (ExceptionA | ExceptionB e) { 
    // common code to be called for both... 
    // .... 
    handleException(e) 
} 

//.... 
void handleException(ExceptionA e) { 
    // code for A 
} 
//.... 
void handleException(ExceptionB e) { 
    // code for B 
} 

W ten sposób najpierw wykonać wspólne działania na dwóch kwestiach, potem masz wspólny kod dla każdego z wyjątków w odpowiednia metoda. W ten sposób nie trzeba używać instancji instanceof lub ifs.

Kolejny sposób to zrobić tylko za pomocą konstruktów Java jest przez umieszczenie w końcu także:

boolean fail = false; 

try { 
    // your code 
} catch (ExceptionA a) { 
    // exceptionA specific handling 
    fail = true; 
} catch (ExceptionB b) { 
    // exceptionB specific handling 
    fail = true; 
} finally { 
    if (fail) { 
     // common handling 
    } 
} 
+0

Ładne rozwiązania! –

+0

Czy sam wypróbowałeś najlepsze rozwiązanie? To nie działa dla mnie, ponieważ kompilator nie może rozwiązać metody 'handleException (ExceptionA | ExceptionB)'. Będziesz musiał zmienić podpis na 'handleException (Exception e)', który pokonuje cel ... – r0estir0bbe

Powiązane problemy