Podczas wypróbowania funkcji Multi-catch znalazłem w mojej m1()
metodzie wszystko działa dobrze zgodnie z oczekiwaniami.
Jednak w m2()
tym samym kodzie nie kompiluje się. Właśnie zmieniłem składnię, aby zmniejszyć liczbę wierszy kodu.
public class Main {
public int m1(boolean bool) {
try {
if (bool) {
throw new Excep1();
}
throw new Excep2();
//This m1() is compiling abs fine.
} catch (Excep1 | Excep2 e) {
return 0;
}
}
public int m2(boolean b) {
try {
throw b ? new Excep1() : new Excep2();
//This one is not compiling.
} catch (Excep1 | Excep2 e) {
return 0;
}
}
private static interface I {
}
private static class Excep1 extends Exception implements I {
}
private static class Excep2 extends Exception implements I {
}
}
Dlaczego metoda się nie m2()
kompiluje?
Odpowiedzi:
Rodzaj wyrażenia
jest
Exception
, ponieważ jest to powszechny nadtypExcep1
iExcep2
.Jednak nie łapiesz
Exception
, więc kompilator narzeka na to.Jeśli złapiesz
Exception
, przejdzie kompilacja:Próbowałem znaleźć wpis JLS, który wyjaśnia typ warunkowego wyrażenia trójskładnikowego w twoim przykładzie.
Wszystko, co mogłem znaleźć, to to, że to konkretne wyrażenie to 15.25.3. Odwołanie Wyrażenie warunkowe .
Nie jestem do końca pewien, czy liczy się ono jako wyrażenie poli czy samodzielne. Wydaje mi się, że jest samodzielny (ponieważ wyrażenia poli obejmują kontekst przypisania lub kontekst wywołania, i nie sądzę, aby
throw
oświadczenie liczyło się jako jedno z nich).W przypadku samodzielnego wyrażenia: „Jeśli drugi i trzeci operand mają ten sam typ (który może być typem pustym), to jest to typ wyrażenia warunkowego”.
W twoim przypadku, drugi i argumenty trzecie mają trzy podstawowe rodzaje -
Object
,Throwable
iException
- rodzaj ekspresji musi być jednym z dwóch ostatnich, ponieważ „The Expression w oświadczeniu rzutów musi albo oznacza zmienną lub wartość typu referencyjnego który można przypisać (§5.2) do typu Throwable. ”Wygląda na to, że kompilator wybiera najbardziej typowy typ (
Exception
), a zatemcatch (Exception e)
rozwiązuje błąd kompilacji.Próbowałem również zastąpić dwa niestandardowe wyjątki dwiema podklasami
IOException
, w którym to przypadkucatch (IOException e)
rozwiązuje błąd kompilacji.źródło
Excep1
lubExcep2
. Może być tylkoException
.Mylisz kompilator z tą linią:
Kompilator widzi, że wynikiem wyrażenia (po lewej stronie rzutu) jest wspólna superklasa między Except1 i Except2, czyli Exception, a zatem rzucany przez ciebie typ efektywny staje się Exception. Instrukcja catch nie może wykryć, że próbujesz wyrzucić Excep1 lub Except2.
źródło
Java ogranicza przechwytywanie lub deklarowanie wszystkich typów wyjątków, które metoda może zgłaszać,
To poszukiwanie wspólnych zarówno dla rodzica (/) Wyjątki i wszyscy oczekują, aby złapać albo uznać jako rzuca, na przykład jeśli
Excep1
rozciągaThrowable
trzeba będzie złapać także ThrowableW pierwszym przypadku Java jest pewna, że rzucasz
Excep1
lubExcep2
źródło