Natknąłem się na kod wyglądający mniej więcej tak:
void run() {
try {
doSomething();
} catch (Exception ex) {
System.out.println("Error: " + ex);
throw ex;
}
}
void doSomething() {
throw new RuntimeException();
}
Ten kod mnie zaskakuje, ponieważ wygląda na to, że run()
-metoda jest w stanie wyrzucić Exception
, ponieważ łapie, Exception
a następnie ponownie rzuca, ale metoda nie jest zadeklarowana do rzucenia Exception
i najwyraźniej nie musi być. Ten kod dobrze się kompiluje (przynajmniej w Javie 11).
Oczekuję , że będę musiał zadeklarować throws Exception
w run()
metodzie.
Dodatkowe informacje
W podobny sposób, jeśli doSomething
zostanie zadeklarowany jako rzut, IOException
to IOException
musi być zadeklarowany tylko w run()
metodzie, nawet jeśli Exception
zostanie złapany i ponownie rzucony.
void run() throws IOException {
try {
doSomething();
} catch (Exception ex) {
System.out.println("Error: " + ex);
throw ex;
}
}
void doSomething() throws IOException {
// ... whatever code you may want ...
}
Pytanie
Java zazwyczaj lubi jasność, jaki jest powód tego zachowania? Czy zawsze tak było? Co w specyfikacji języka Java pozwala run()
metodzie nie musieć deklarować throws Exception
w powyższych fragmentach kodu? (Gdybym dodał, IntelliJ ostrzega mnie, że Exception
nigdy nie zostanie wyrzucony).
javac
- natknąłem się na przypadki, w których kompilator Eclipse był bardziej łagodny.-source 1.6
flagą powoduje błąd kompilacji zgodnie z oczekiwaniami. Kompilacja z kompatybilności źródło 7 czy nie podnieść błąd kompilacjiIn detail, in Java SE 7 and later, when you declare one or more exception types in a catch clause, and rethrow the exception handled by this catch block, the compiler verifies that the type of the rethrown exception meets the following conditions : 1. 1. The try block is able to throw it. 2. There are no other preceding catch blocks that can handle it. 3. It is a subtype or supertype of one of the catch clause's exception parameters.
Odpowiedzi:
Nie skanowałem tego,
JLS
co zadałeś w swoim pytaniu, więc proszę, odpowiedz na to z odrobiną soli. Chciałem napisać komentarz, ale byłby zbyt duży.Czasami
javac
wydaje mi się zabawne, jak to jest całkiem „inteligentne” w niektórych przypadkach (jak w twoim przypadku), ale pozostawia wiele innych rzeczy do załatwienia późniejJIT
. W tym przypadku kompilator „może powiedzieć”,RuntimeException
że zostanie złapany tylko a . To oczywiste, że to jedyna rzecz, do której wrzucaszdoSomething
. Jeśli nieznacznie zmienisz kod na:zobaczysz inne zachowanie, ponieważ teraz
javac
możesz stwierdzić,Exception
że rzucasz nowe, niezwiązane z tym, które złapałeś.Ale rzeczy są dalekie od ideału, możesz ponownie „oszukać” kompilator poprzez:
IMO z
ex2 = ex;
tego powodu nie powinno ponownie zawieść, ale tak się dzieje.Na wypadek gdyby zostało to skompilowane
javac 13+33
źródło
ex2
wyjątek zostanie zgłoszony, został pierwotnie utworzony jako,Exception
ale następnie został ponownie przypisanyex
, a zatem kompilator nie może być inteligentny.JLS
może przyjść ktoś, kto ma pasję i dostarczył potrzebne cytaty, aby to udowodnić; niestety ich nie mam.ex = ex;
), heurystyka nie jest już stosowana. To zachowanie wydaje się być stosowane na wszystkich poziomach źródła od 7 do 11 i prawdopodobnie 13