Java недоступна ошибка компилятора блока catch

java scjp

36386 просмотра

6 ответа

Почему в Java мы можем поймать, Exceptionдаже если он не генерируется , но мы не можем поймать его подкласс (кроме «непроверенных» RuntimeExceptionи его подклассов). Пример кода:

class Test {
    public static void main(String[] args) {
        try {
            // do nothing
        } catch (Exception e) {
            // OK           
        }

        try {
            // do nothing
        } catch (IOException e) {
               // COMPILER ERROR: Unreachable catch block for IOException.
               //This exception is never thrown from the try statement body
        }       
    }
}

Есть идеи?

Автор: bary Источник Размещён: 12.11.2019 09:11

Ответы (6)


25 плюса

Решение

А RuntimeExceptionможет быть брошено любым кодом. Другими словами, компилятор не может легко предсказать, какой код может его генерировать. А RuntimeExceptionможет быть пойман catch(Exception e)блоком.

IOExceptionоднако, это проверенное исключение - это могут делать только вызовы методов, которые объявлены как сгенерированные. Компилятор может быть (разумно) уверен, что это не может произойти, если нет вызовов метода, которые объявлены для его выброса.

Компилятор Java просто не учитывает ситуацию «в блоке try нет кода вообще» - он всегда позволяет вам перехватывать непроверенные исключения, поскольку во всех разумных сценариях будет код, который потенциально может вызвать непроверенное исключение.

Из раздела 14.21 JLS:

Блок перехвата C доступен, если выполняются оба следующих условия:

  • Некоторое выражение или оператор throw в блоке try достижимо и может генерировать исключение, тип которого можно назначить параметру предложения catch C. (Выражение считается достижимым, если самый внутренний оператор, содержащий его, доступен).
  • В инструкции try нет более раннего блока catch A, так что тип параметра C совпадает с типом параметра A или является его подклассом.

Возможно, компилятор должен понимать, что в вашем блоке try нет выражений в вашем первом случае ... похоже, это все еще недоступное предложение catch для меня.

РЕДАКТИРОВАТЬ: Как отмечено в комментариях, раздел 14.20 содержит это:

Это ошибка времени компиляции, если catchпредложение перехватывает проверенный тип исключения E1, но не существует проверенного типа исключения E2 , так что выполняются все следующие условия:

  • E2 <: E1
  • tryБлок , соответствующий catchпункту может бросить E2
  • Ни один из предшествующих catchблоков непосредственно включенного оператора try не перехватывает E2 или супертип E2 .

если E1 не является исключением класса.

Так что, похоже, это то, что вы на самом деле недовольны, но спецификация не так ясна, как могла бы быть с точки зрения недоступных блоков улова в 14.21.

Автор: Jon Skeet Размещён: 05.05.2011 03:01

5 плюса

Исключения ввода-вывода могут быть перехвачены, только если компилятор предсказывает, что в коде может быть что-то, вызывающее исключение IOException. Таким образом, вы получаете предупреждение о том, что исключение IO никогда не выдается из тела оператора try (так как в теле try нет ничего).

Автор: Maveňツ Размещён: 12.02.2014 07:25

3 плюса

Поскольку для проверенных исключений метод, который их выбрасывает, должен явно указать этот факт с помощью ключевого слова throws, поэтому, если в вашем случае блок не имеет исключения throws IOException, у компилятора есть информация, которую невозможно исключить для IOException быть брошенным, поэтому, что бы вы ни делали после ловли, это было бы недоступно.

Автор: abalogh Размещён: 05.05.2011 03:01

3 плюса

Вы не можете поймать неприброшенные проверенные исключения, потому что они не могут быть выброшены. Вы можете поймать, Exceptionпотому что непроверенное исключение времени выполнения является ExceptionИ МОЖЕТ быть выброшено.

Автор: Isaac Truett Размещён: 05.05.2011 03:01

1 плюс

IOExceptionявляется проверенным исключением, которое генерируется только кодом, связанным с IO. Поскольку ваш блок try ничего не делает, ничего, связанного с IO, никогда не произойдет, исключения IOException никогда не будут выброшены, поэтому блок catch никогда не будет выполнен, и компилятор не позволит вам обойти это. Как вы сказали, исключение может относиться к непроверенным исключениям времени выполнения, которые могут возникнуть в любой момент. Это основное различие между непроверенными и проверенными исключениями, и именно поэтому компилятор не заставляет код перехватывать все возможные исключения во время выполнения.

Автор: Anthony Accioly Размещён: 05.05.2011 03:04

0 плюса

Просто Java предполагает, что любая строка кода может генерировать общий Exceptionили Throwable, т.е. OutOfMemoryExceptionкоторая представляет собой Errorскорее Exception. То же самое относится и к NPE.

IOException это конкретное исключение, которое может быть выдано только управляемым кодом, поэтому, если у вас нет вызовов ввода-вывода в блоке catch, ваш компилятор не сможет его перехватить.

Просто для сравнения с миром C # в C # такой код будет компилироваться, но это будет концептуальной ошибкой, поскольку, если вы ничего не делаете, вы не достигнете блока catch. Такой инструмент, как ReSharper, может предупредить вас об этом.

Автор: usr-local-ΕΨΗΕΛΩΝ Размещён: 05.05.2011 03:01
Вопросы из категории :
32x32