Почему java не обнаруживает недостижимый блок catch, если я использую несколько блоков catch?
исследования следующим образом:
static private void foo() {
try {
throw new FileNotFoundException();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
этот код компилируется хорошо, несмотря на последний блок catch на самом деле недоступен.
теперь давайте комментария throw new FileNotFoundException();
строка
выполнить:
Упс! мы видим
Unreachable catch block for FileNotFoundException. This exception is never thrown from the try statement body
странно. Почему Java использовать двойные стандарты для этих situatons?
обновление для @Peter Rader
static private void foo(FileNotFoundException f) {
try {
throw f;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
работа, а также с вызовом конструктора
обновление
I заметил, что в разных версиях Java-компилятора я вижу разные результаты компиляции этого кода.
public class RethowTest {
public static void main(String[] args) {
try {
throw new FileNotFoundException();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
throw e;
}
}
}
на моем локальном ПК: java 1.7.0_45 -
C:Program FilesJavajdk1.7.0_45bin>javac D:DNN-ProjectDNN-ProjectsrcmainjavaexceptionsAndAssertionsRethowTest.java
D:DNN-ProjectDNN-ProjectsrcmainjavaexceptionsAndAssertionsRethowTest.java:15: warning: unreachable catch clause
} catch (IOException e) {
^
thrown type FileNotFoundException has already been caught
1 warning
java 1.6.0_38
D:DNN-ProjectDNN-ProjectsrcmainjavaexceptionsAndAssertionsRethowTest.java:16: unreported exception java.io.IOException; must be caught or declared to be thrown
throw e;
^
1 error
http://www.compileonline.com/compile_java_online.php (Javac 1.7.0_09) -
HelloWorld.java:9: warning: unreachable catch clause
} catch (IOException e) {
^
thrown type FileNotFoundException has already been caught
1 warning
3 ответов
правила достижимости определены в Java 8 JLS 14.21 (и Java 7) следующим образом:
блок catch c достижим, если выполняются оба следующих условия:
либо тип параметра C является непроверенным типом исключения или исключением, либо суперклассом исключения, или какое-либо выражение или оператор throw в блоке try достижимы и могут вызывать проверенное исключение, тип которого присваивается типу параметра Си. (выражение достижимо, если самый внутренний оператор, содержащий его, достижим.)
см. §15.6 для нормального и резкого завершения выражений.
в операторе try нет более раннего блока catch A, так что тип параметра C совпадает с подклассом типа параметра A.
обратите внимание, что правила не запрещают ваш пример кода. Второй улов блок не отвечает критериям второго маркера.
(в оригинальной версии примера вы поймали Exception
. Рассуждение о достижимости было бы другим, но ответ тот же - действительный код.)
это несовместимо? Например, вы можете утверждать, что это так.
почему они не рассмотрели этот случай в правилах достижимости? Я не знаю. Вам нужно спросить дизайнеров Java!! Однако:
на разработки правил достижимости должно быть значительно сложнее, чтобы справиться с этим. Лишнее (ненужное?) сложность спецификации вызывает озабоченность.
вы можете утверждать, что эта несогласованность ничего не нарушает. Правила достижимости на самом деле просто способ забрать потенциал ошибки в коде пользователей. Это не связано с безопасностью типа или предсказуемо выполнение; т. е. материал,который "сломает" семантику Java runtime.
Если бы они изменили спецификацию сейчас, это сделало бы недействительной небольшую часть действительных и рабочих программ Java. Это не очень хорошая идея, учитывая, что стабильность является одной из основных точек продажи Java.
С другой стороны, я не вижу технических причин, почему они не мог рассмотрели эту "несогласованность" в спекуляция.
вы отметили, что некоторые компиляторы Java дают предупреждающее сообщение на 2nd catch
. Это нормально. Компилятору Java разрешено давать предупреждения о вещах, которые являются (технически) законным Java-кодом.
Если бы они были ошибками, это было бы технически ошибкой компилятора ... согласно моему чтению JLS.
на catch (Exception ...)
блок поймает исключения времени выполнения. Она никогда не бывает недостижимой в принципе.
FileNotFoundException
- это проверенное исключение. Блок catch для него доступен, только если что-то в блоке try бросает его или один из его дочерних классов.
[в ответ на запросы]
если вы instanciate new FileNotFoundException()
вы вызываете констуктора класса FileNotFoundException
. В этом конструкторе исключение IOException может быть theroretically вызвано вызовом собственного метода fillInStackTrace
- компилятор может не знать, что содержимое конструктора, возможно, a IOException
будет брошен.
посмотреть в этой статье: https://community.oracle.com/thread/1445008?start=0 в Примере.
если компилятор заглядывает в конструктор FileNotFoundException()
для каждого события: его a накладные расходы java пренебрегают производительностью.