Исключение, брошенное в улов и, наконец, пункт - PullRequest
138 голосов
/ 23 сентября 2010

На вопрос для 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.

Ответы [ 12 ]

146 голосов
/ 23 сентября 2010

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

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

Примечаниечто применимые блоки catch или finally включают в себя:

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

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

37 голосов
/ 23 сентября 2010

Вот что Википедия говорит о предложении 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 наконец, предложение называется ... (помните, мы только что поймали Exception i и выбросили MyExc2) по сути, 2 выводится на экран ... и после 2 выводится на экран, выдается исключение MyExc1. MyExc1 обрабатывается методом public static void main(...).

Выход:

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

Лектор правильный! : -)

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

32 голосов
/ 27 марта 2014

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

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

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

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

21 голосов
/ 23 сентября 2010

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

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

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

9 голосов
/ 23 сентября 2010

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

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

q () -> брошенный new Exception -> main catch Exception -> throw new Exception - > finally бросить новый exception (а тот из catch "потерян")

3 голосов
/ 23 сентября 2010

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

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()'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
}
1 голос
/ 25 ноября 2013

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

Cheers.

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

}
////////////////////////////////////////////////// 
0 голосов
/ 16 мая 2019

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

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

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

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

0 голосов
/ 20 апреля 2019

Чтобы справиться с подобной ситуацией, то есть обработать исключение, вызванное блоком 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"
0 голосов
/ 27 декабря 2017
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/

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