Исключение брошено внутри блока catch – будет ли оно поймано снова?

Это может показаться вопросом программирования 101, и я подумал, что знаю ответ, но теперь мне нужно дважды проверить. В этом fragmentе кода ниже будет ли исключение, заброшенное в первом блоке catch, пойманным общим блоком catch Exception ниже?

try { // Do something } catch(IOException e) { throw new ApplicationException("Problem connecting to server"); } catch(Exception e) { // Will the ApplicationException be caught here? } 

Я всегда думал, что ответ будет отрицательным, но теперь у меня есть странное поведение, которое может быть вызвано этим. Ответ, вероятно, одинаковый для большинства языков, но я работаю на Java.

Нет, поскольку новый throw не находится в блоке try напрямую.

Нет. Это очень легко проверить.

 public class Catch { public static void main(String[] args) { try { throw new java.io.IOException(); } catch (java.io.IOException exc) { System.err.println("In catch IOException: "+exc.getClass()); throw new RuntimeException(); } catch (Exception exc) { System.err.println("In catch Exception: "+exc.getClass()); } finally { System.err.println("In finally"); } } } 

Должен печатать:

 В catch IOException: class java.io.IOException
 В конце
 Исключение в streamе "main" java.lang.RuntimeException
         на Catch.main (Catch.java:8) 

Технически это могло быть ошибкой компилятора, зависимым от реализации, неопределенным поведением или чем-то еще. Тем не менее, JLS довольно хорошо прибита, и компиляторы достаточно хороши для такого рода простых вещей (общий угол корпуса может быть другим).

Также обратите внимание: если вы обмениваетесь двумя блоками catch, он не будет компилироваться. Второй улов будет совершенно недостижим.

Обратите внимание, что блок finally всегда работает, даже если выполняется блок catch (кроме глупых случаев, таких как бесконечные петли, прикрепление через интерфейс инструментов и уничтожение streamа, переписывание байт-кода и т. Д.).

Спецификация языка Java говорит в разделе 14.19.1:

Если выполнение блока try завершается внезапно из-за броска значения V, тогда есть выбор:

  • Если тип времени выполнения V присваивается Параметру любого предложения catch в инструкции try, тогда выбирается первое (крайнее левое) предложение catch. Значение V присваивается параметру выбранного предложения catch, и выполняется блок этого условия catch. Если этот блок завершается нормально, то инструкция try завершается нормально; если этот блок внезапно завершится по какой-либо причине, то оператор try завершится внезапно по той же причине.

Ссылка: http://java.sun.com/docs/books/jls/second_edition/html/statements.doc.html#24134

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

Одна связанная и запутанная вещь, которую нужно знать, заключается в том, что в структуре try- [catch] -finally блок finally может генерировать исключение, и если это так, любое исключение, созданное блоком try или catch, теряется. Это может сбить с толку в первый раз, когда вы это увидите.

Если вы хотите выбросить исключение из блока catch, вы должны сообщить свой метод / class / etc. что ему нужно выбросить указанное исключение. Вот так:

 public void doStuff() throws MyException { try { //Stuff } catch(StuffException e) { throw new MyException(); } } 

И теперь ваш компилятор не будет кричать на вас 🙂

Нет. Как сказал Крис Джет-Янг, он будет взят до следующей попытки в иерархии.

Как сказано выше …
Я бы добавил, что если у вас возникнут проблемы с тем, что происходит, если вы не можете воспроизвести проблему в отладчике, вы можете добавить трассировку перед повторным броском нового исключения (с хорошим старым System.out.println хуже , с хорошей системой регистрации, например log4j).

Второй захват не будет пойман. Каждое исключение захватывается только внутри блока try. Вы можете вложить попытки (хотя это не хорошая идея):

 try { doSomething(); } catch (IOException) { try { doSomething(); } catch (IOException e) { throw new ApplicationException("Failed twice at doSomething" + e.toString()); } } catch (Exception e) { } 

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

Старая запись, но переменная «e» должна быть уникальной:

 try { // Do something } catch(IOException ioE) { throw new ApplicationException("Problem connecting to server"); } catch(Exception e) { // Will the ApplicationException be caught here? } 
  • .NET. Каков наилучший способ реализации «catch all exceptions handler»
  • Что такое «случайное исключение»?
  • исключения try-catch в Swift
  • Что произойдет, если блок finally выдает исключение?
  • Насколько медленны исключения .NET?
  • Почему Catch (Exception) почти всегда является плохой идеей?
  • Java List.add () UnsupportedOperationException
  • Должен ли я использовать AppDomain.CurrentDomain.BaseDirectory или System.Environment.CurrentDirectory?
  • Как я могу написать пользовательские исключения?
  • Тихие сбои в C #, казалось бы, необработанные исключения, которые не приводят к сбою программы
  • Каким образом исключения C ++ замедляют работу кода, если нет исключений?
  • Interesting Posts

    Почему autoReconnect = true не работает?

    Программы при запуске в Linux

    Как выполнить UPSERT, чтобы я мог использовать как новые, так и старые значения в части обновления

    Как удалить всю папку и содержимое?

    Разбор строк в Java с вкладкой «\ t» разделителя с использованием split

    Как Windows 7 решает, какой маршрут нужно предпринять, если существуют 2 подключения к интернет-источнику? (Например, беспроводной и Ethernet-маршрутизатор)

    Использование пропускной способности удаленного рабочего стола Microsoft

    stdlib и цветной выход в C

    Оператор перегрузки <<: невозможно привязать lvalue к 'std :: basic_ostream &&’

    Как заставить Internet Explorer отображать в стандартном режиме и НЕ в Quirks?

    Как наследовать конструкторы?

    Не удается получить доступ к родительским элементам при работе с аннотациями макросов

    SDK Google Apps Marketplace + OOuth 2 общего доступа домена

    как установить значение для диапазона с помощью JQuery

    Заказ вызова конструктора в виртуальном наследовании

    Давайте будем гением компьютера.