Я наткнулся на код, который выглядит примерно так:
void run() {
try {
doSomething();
} catch (Exception ex) {
System.out.println("Error: " + ex);
throw ex;
}
}
void doSomething() {
throw new RuntimeException();
}
Этот код удивляет меня, потому что он выглядит так, как будто run()
-method способен генерировать Exception
, так как он перехватывает Exception
и затем перебрасывает его, но метод не объявлен как throw Exception
и, очевидно, не нуждается в этом. Этот код прекрасно компилируется (по крайней мере, в Java 11).
Я ожидал бы, что мне придется объявить throws Exception
в run()
методе.
Дополнительная информация
Аналогичным образом, если doSomething
объявлено, что оно выбрасывает, IOException
тогда IOException
нужно только объявить в run()
-методе, даже если Exception
он пойман и переброшен.
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 ...
}
Вопрос
Java обычно любит ясность, в чем причина такого поведения? Это всегда было так? Что в спецификации языка Java позволяетrun()
методу не объявлять throws Exception
в приведенных выше фрагментах кода? (Если я добавлю это, IntelliJ предупредит меня, что Exception
никогда не бросается).
-source 1.6
флагом вызывает ошибку компиляции, как и ожидалось. Компиляция с исходным кодом совместимости 7 никак не поднимет ошибку компиляции
In 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.
javac
- я сталкивался со случаями, когда Eclipse-компилятор был более снисходительным.