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

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

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.

Ответ 1

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

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

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

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

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

Ответ 2

Это то, что Wikipedia говорит о предложении finally:

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

Разрежьте вашу программу.

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

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

Итак,

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

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

Вывод:

"132Exception в главном потоке MyExc1"

Лектер прав!: -)

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

Ответ 3

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

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

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

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

Ответ 4

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

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

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

Ответ 5

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

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

q() брошен new Exception main catch Exception throw new Exception finally введите новый exception (и один из catch потерян)

Ответ 6

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

Exception currentException = null;

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

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

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() finally block
            throw( new MyExc2() ); // <-- currentException = MyExc2
        }
        finally {
             // <-- currentException = MyExc2, thrown from main() catch block
            System.out.print(2);
            throw( new MyExc1() ); // <-- currentException = MyExc1
        }

    }  // <-- At application exit, currentException = MyExc1, from main() 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
}

Ответ 7

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

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

/////////////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!";

}
////////////////////////////////////////////////// 

Ответ 8

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

  • Печать "1".
  • finally в q напечатать "3".
  • finally в main напечатать "2".

Ответ 9

Просто догадайтесь, но блок "finally" всегда выполняется. Итак, я предполагаю, что, поскольку в блоке finally есть исключение, которое имеет приоритет.

Ответ 10

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/

Ответ 11

Чтобы справиться с такой ситуацией, то есть обработать исключение, вызванное блоком finally. Вы можете окружить блок finally блоком try: Посмотрите на приведенный ниже пример в python:

try:
   fh = open("testfile", "w")
   try:
      fh.write("This is my test file for exception handling!!")
   finally:
      print "Going to close the file"
      fh.close()
except IOError:
   print "Error: can\'t find file or read data"

Ответ 12

Логика ясна до завершения печати 13. Затем исключение, генерируемое в q(), перехватывается catch (Exception i) в main() и new MyEx2() готов к new MyEx2(). Однако, прежде чем вызвать исключение, блок finally должен быть выполнен первым. Затем вывод становится new MyEx1() 132 и, finally просит new MyEx1() другое исключение new MyEx1().

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

Таким образом, в этой программе исключение MyEx2 проглатывается, а MyEx1 выбрасывается. Это исключение выбрасывается из main() и больше не перехватывается, поэтому JVM останавливается и в результате выводится 132Exception in thread main MyExc1.

По сути, если у вас есть предложение finally в предложении try/catch, команда finally будет выполнена ПОСЛЕ перехвата исключения, но ДО создания любого захваченного исключения, и ТОЛЬКО самое последнее исключение будет выброшено в конце.

Ответ 13

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

boolean allOk = false;
try{
  q();
  allOk = true;
} finally {
  try {
     is.close();
  } catch (Exception e) {
     if(allOk) {
       throw new SomeException(e);
     }
  }
}