Исключение, брошенное в catch и finally clause

На вопрос для Java в университете был этот fragment кода:

class MyExc1 extends Exception {} class MyExc2 extends Exception {} class MyExc3 extends MyExc2 {} public class C1 { public static void main(String[] args) throws Exception { try { System.out.print(1); q(); } catch (Exception i) { throw new MyExc2(); } finally { System.out.print(2); throw new MyExc1(); } } static void q() throws Exception { try { throw new MyExc1(); } catch (Exception y) { } finally { System.out.print(3); throw new Exception(); } } } 

Меня попросили дать свой результат. Я ответил 13Exception in thread main MyExc2 , но правильный ответ – 132Exception in thread main MyExc1 . Почему это так? Я просто не могу понять, куда идет MyExc2.

Основываясь на чтении вашего ответа и видении того, как вы, вероятно, придумали его, я считаю, что вы считаете, что «исключение в процессе» имеет «приоритет». Иметь ввиду:

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

Обратите внимание, что применимые блоки catch или finally include:

Когда новое исключение выбрасывается в блок catch, новое исключение по-прежнему подчиняется блоку finally catch, если таковое имеется.

Теперь верните выполнение, помня, что всякий раз, когда вы нажимаете throw , вы должны прервать отслеживание текущего исключения и начать отслеживать новое исключение.

Это то, что Wikipedia говорит о окончательной статье:

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

Давайте проанализируем вашу программу.

 try { System.out.print(1); q(); } 

Таким образом, 1 будет выводиться на экран, затем вызывается q() . В q() генерируется исключение. Исключением затем вызывается Exception y но он ничего не делает. Затем выполняется предложение finally (оно должно), поэтому на экран будет выведено 3 . Потому что (в методе q() есть исключение, заброшенное в предложении finally , также метод q() передает исключение в родительский стек (путем throws Exception в объявлении метода) new Exception() будет выброшен и пойман catch ( Exception i ) , исключение MyExc2 будет MyExc2 (теперь добавьте его в стек исключений), но сначала будет выполнен первый MyExc2 в main блоке.

Итак,

 catch ( Exception i ) { throw( new MyExc2() ); } finally { System.out.print(2); throw( new MyExc1() ); } 

Предложение finally называется … (помните, мы только что поймали Exception i и выбросили MyExc2 ) по существу, 2 напечатано на экране … и после того, как 2 будет напечатано на экране, MyExc1 исключение MyExc1 . MyExc1 обрабатывается public static void main(...) методом public static void main(...) .

Вывод:

“132Exception в главном streamе MyExc1”

Лектор – это правильно! 🙂

В сущности , если у вас наконец есть предложение try / catch, то, наконец, будет выполнено ( после того, как поймать исключение, прежде чем выбросить исключенное исключение)

Цитата из JLS 9: 14.20.2. Выполнение try-finally и try-catch-finally

Если блок catch завершается внезапно для причины R, тогда выполняется блок finally. Тогда есть выбор:

  • Если окончательный блок завершается нормально, то оператор try внезапно завершается по причине R.

  • Если блок finally завершается внезапно для разума S, то оператор try внезапно завершается по причине S (и причина R отбрасывается).

Предложение finally выполняется даже тогда, когда исключение выбрасывается из любого места в блоке try / catch.

Поскольку это последний, который будет выполнен в main и он выдает исключение, это исключение, которое видят вызывающие.

Следовательно, важно убедиться, что предложение finally ничего не бросает, потому что оно может проглатывать исключения из блока try .

method не может throw два исключения одновременно. Он всегда будет бросать последнее exception , которое в этом случае будет всегда одним из блока finally .

Когда выбрано первое исключение из метода q() , оно будет ловить, а затем проглотить исключение, исключенное из блока finally.

q () -> throw new Exception -> main catch Exception -> throw new Exception -> finally выкинуть новое exception (и одно из catch «потеряно»)

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

 Exception currentException = null; 

Поскольку каждое исключение выбрасывается, «currentException» устанавливается в это исключение. Когда приложение заканчивается, если currentException равно! = Null, тогда среда выполнения сообщает об ошибке.

Кроме того, блоки finally всегда запускаются до выхода метода. Затем вы можете передать fragment кода:

 public class C1 { public static void main(String [] argv) throws Exception { try { System.out.print(1); q(); } catch ( Exception i ) { // <-- currentException = Exception, as thrown by q()'s finally block throw( new MyExc2() ); // <-- currentException = MyExc2 } finally { // <-- currentException = MyExc2, thrown from main()'s catch block System.out.print(2); throw( new MyExc1() ); // <-- currentException = MyExc1 } } // <-- At application exit, currentException = MyExc1, from main()'s finally block. Java now dumps that to the console. static void q() throws Exception { try { throw( new MyExc1() ); // <-- currentException = MyExc1 } catch( Exception y ) { // <-- currentException = null, because the exception is caught and not rethrown } finally { System.out.print(3); throw( new Exception() ); // <-- currentException = Exception } } } 

Порядок выполнения приложения:

 main() { try q() { try catch finally } catch finally } 

Хорошо известно, что блок finally выполняется после try и catch и всегда выполняется … Но, как вы видели, это немного сложно, иногда проверяйте этот fragment кода ниже, и вы убедитесь, что заявления о возврате и броске «всегда делайте то, что они должны делать в том порядке, в котором мы ожидаем, что тема.

Приветствия.

 /////////////Return dont always return/////// try{ return "In Try"; } finally{ return "In Finally"; } //////////////////////////////////////////// //////////////////////////////////////////// while(true) { try { return "In try"; } finally{ break; } } return "Out of try"; /////////////////////////////////////////// /////////////////////////////////////////////////// while (true) { try { return "In try"; } finally { continue; } } ////////////////////////////////////////////////// /////////////////Throw dont always throw///////// try { throw new RuntimeException(); } finally { return "Ouuuups no throw!"; } ////////////////////////////////////////////////// 

Я думаю, вам просто нужно пройти, finally блоки:

  1. Печать «1».
  2. finally в q напечатайте «3».
  3. finally в main печати «2».
 class MyExc1 extends Exception {} class MyExc2 extends Exception {} class MyExc3 extends MyExc2 {} public class C1 { public static void main(String[] args) throws Exception { try { System.out.print("TryA L1\n"); q(); System.out.print("TryB L1\n"); } catch (Exception i) { System.out.print("Catch L1\n"); } finally { System.out.print("Finally L1\n"); throw new MyExc1(); } } static void q() throws Exception { try { System.out.print("TryA L2\n"); q2(); System.out.print("TryB L2\n"); } catch (Exception y) { System.out.print("Catch L2\n"); throw new MyExc2(); } finally { System.out.print("Finally L2\n"); throw new Exception(); } } static void q2() throws Exception { throw new MyExc1(); } } 

Порядок:

 TryA L1 TryA L2 Catch L2 Finally L2 Catch L1 Finally L1 Exception in thread "main" MyExc1 at C1.main(C1.java:30) 

https://www.compilejava.net/

Я думаю, что это решает проблему:

 boolean allOk = false; try{ q(); allOk = true; } finally { try { is.close(); } catch (Exception e) { if(allOk) { throw new SomeException(e); } } } 
  • Кто удаляет память, выделенную во время «новой» операции, которая имеет исключение в конструкторе?
  • UnsupportedOperationException при попытке удалить из списка, возвращаемого Array.asList
  • Почему я получаю «должен быть пойман или объявлен брошен» в моей программе?
  • Кто вызывает метод прерывания Java (), если нет?
  • Проверено или исключено исключение
  • Java: глобальный обработчик исключений
  • Почему неправильный пароль приводит к тому, что «Заполнение недопустима и не может быть удалено»?
  • Почему существует NotImplementedException?
  • Как узнать точную строку кода, где было вызвано исключение?
  • Когда нужно поймать java.lang.Error?
  • Visual Studio: как разбить обработанные исключения?
  • Давайте будем гением компьютера.