Ich bin auf Code gestoßen, der ungefähr so aussieht:
void run() {
try {
doSomething();
} catch (Exception ex) {
System.out.println("Error: " + ex);
throw ex;
}
}
void doSomething() {
throw new RuntimeException();
}
Dieser Code überrascht mich, weil es so aussieht, als ob die run()
-Methode in der Lage ist, ein zu werfen Exception
, da es es fängt Exception
und dann erneut wirft, aber die Methode ist nicht zum Werfen deklariert Exception
und muss es anscheinend nicht sein. Dieser Code wird einwandfrei kompiliert (zumindest in Java 11).
Meine Erwartung wäre, dass ich throws Exception
in der run()
Methode deklarieren müsste .
Zusatzinformation
In ähnlicher Weise muss, wenn doSomething
zum Werfen deklariert wird, IOException
nur IOException
in der Methode deklariert werden run()
, obwohl Exception
es gefangen und erneut geworfen wird.
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 ...
}
Frage
Java mag normalerweise Klarheit. Was ist der Grund für dieses Verhalten? War es schon immer so? Was in der Java-Sprachspezifikation erlaubt es der run()
Methode, nicht throws Exception
in den obigen Codefragmenten zu deklarieren ? (Wenn ich es hinzufügen würde, warnt mich IntelliJ, dass Exception
es nie geworfen wird).
javac
- Ich bin auf Fälle gestoßen, in denen der Eclipse-Compiler milder war.-source 1.6
Flag führt erwartungsgemäß zu einem Kompilierungsfehler. Das Kompilieren mitIn 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.
Antworten:
Ich habe das nicht durchgesehen,
JLS
wie Sie in Ihrer Frage gefragt haben, also nehmen Sie diese Antwort bitte mit einem Körnchen Salz. Ich wollte einen Kommentar abgeben, aber er wäre zu groß gewesen.Ich finde es manchmal lustig, wie
javac
ziemlich "klug" in einigen Fällen (wie in Ihrem Fall) ist, aber viele andere Dinge müssen später erledigt werdenJIT
. In diesem Fall kann der Compiler nur "erkennen", dass nur aRuntimeException
abgefangen wird. Dies ist offensichtlich, es ist das einzige, was Sie einwerfendoSomething
. Wenn Sie Ihren Code leicht ändern in:Sie werden ein anderes Verhalten sehen, weil Sie jetzt erkennen
javac
können, dass es ein neues gibtException
, das Sie werfen, das nichts mit dem zu tun hat, das Sie gefangen haben.Aber die Dinge sind alles andere als ideal, Sie können den Compiler noch einmal "austricksen" über:
IMO, weil
ex2 = ex;
es nicht wieder scheitern sollte, aber es tut.Nur für den Fall, dass dies mit kompiliert wurde
javac 13+33
quelle
ex2
Ausnahme ausgelöst wird. Sie wurde ursprünglich als erstelltException
, wird dann aber neu zugewiesenex
, und daher kann der Compiler nicht intelligent sein.JLS
könnte kommen und die erforderlichen Zitate liefern, um dies zu beweisen; Leider habe ich sie nicht.ex = ex;
), wird die Heuristik für den Datensatz nicht mehr angewendet. Dieses Verhalten scheint für alle Quellenebenen von 7 bis 11 und wahrscheinlich 13