Почему 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 пренебрегают производительностью.