Что будет первым - наконец-то или поймать блок? - PullRequest
23 голосов
/ 24 июня 2010

Рассмотрим следующий тестовый пример:

public class Main {

    static int a = 0;

    public static void main(String[] args) {
        try {
            test();
            System.out.println("---");
            test2();
        }
        catch(Exception e) {
            System.out.println(a + ": outer catch");
            a++;
        }
    }

    public static void test()
    {
        try {
            throw new Exception();
        }
        catch (Exception e) {
            System.out.println(a + ": inner catch");
            a++;
        }
        finally {
            System.out.println(a + ": finally");
            a++;
        }
    }

    public static void test2() throws Exception
    {
        try {
            throw new Exception();
        }
        finally {
            System.out.println(a + ": finally");
            a++;
        }
    }
}

С выходом:

0: inner catch
1: finally
---
2: finally
3: outer catch

Чем объясняется, почему в test() улов происходит раньше, наконец, а в test2() наоборот?

Ответы [ 8 ]

16 голосов
/ 24 июня 2010

Вот ключевые моменты:

  • В блоке try-(catch)-finally, finally для этого конкретного блока try выполняется последним
  • Вы можете вложите try блоков в другой, и каждый из этих вложенных try блоков может иметь свои finally, которые будут выполняться последними для этих отдельных try блоков

.да, finally выполняется последним, но только для блока try, к которому он прикреплен.

Так, учитывая следующий фрагмент:

try {
    try {
        throw null;
    } finally {
        System.out.println("Finally (inner)");
    }
} catch (Throwable e) {
    System.out.println("Catch (outer)");
}

Это печатает( как видно на ideone.com ):

Finally (inner)
Catch (outer)

Обратите внимание, что:

  • В пределах (inner), Finally является последним (независимо от того, является или нет)любой catch был успешным)
  • Catch (outer) следует Finally (inner), но это потому, что Finally (inner) вложено в другой try блок в (outer)

Аналогично, следующий фрагмент:

    try {
        try {
            throw null;
        } catch (Throwable e) {
            System.out.println("Catch (inner)");
        } finally {
            System.out.println("Finally (inner)");
            throw null;
        }
    } catch (Throwable e) {
        System.out.println("Catch (outer)");
    }

Это печатает ( как видно на ideone.com ):

Catch (inner)
Finally (inner)
Catch (outer)

Ссылки

Смежные вопросы

16 голосов
/ 24 июня 2010

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

7 голосов
/ 24 июня 2010

catch доходит наконец в той же области действия try-catch-finally.

Если в test2 нет улова в области действия try-catch-finally для test2, то он выполняет команду finally перед тем, как покинуть область действия и попасть в более высокий улов.

4 голосов
/ 24 июня 2010

Поскольку блок finally всегда выполняется непосредственно перед выходом из области видимости.Последовательность событий после вызова test2() выглядит следующим образом:

  1. исключение выдается в test2()
  2. Поскольку test2 не имеет блока catch, исключение распространяетсядо вызывающего.
  3. Так как test2 имеет блок finally, он выполняется перед возвратом из метода.
  4. catch в основном методе перехватывает исключение.
2 голосов
/ 24 июня 2010

try - catch и finally используются для избежания ситуаций, когда программа может быть остановлена ​​из-за возникновения нежелательной ошибки во время выполнения программы.

Следующие пункты важны ....

1) Для блока есть только одна попытка ...... любое количество операторов catch для блока и только один, наконец, для блока статистики

2), наконец, опционально.

3) catch также необязателен, но если оператор catch отсутствует, то, наконец, должен появиться.

4) Все перехваты, соответствующие дочерним исключениям, должны появляться перед перехватом для родительского исключения.

5) Независимо от возникновения исключения, операторы, присутствующие в блоке finally, всегда выполняются с одним исключением.

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

Примечание: даже если в блоке try появляется оператор возврата ... tтогда и код в конечном итоге выполняется.

2 голосов
/ 24 июня 2010

Потому что finally - самый последний код, выполняемый в блоке try..catch, независимо от того, было ли исключение выброшено, сгенерировано и затем обработано или не сгенерировано вообще.

Фактически, единственный раз, когда not будет вызван в конечном итоге, - это если JVM завершает работу до того, как его выполнит, или если поток, выполняющий код попытки, будет уничтожен или прерван.* В ответ на комментарии: Java Описание finally

Note: If the JVM exits while the try or catch code is being executed,

тогда блок finally может не выполняться.Аналогично, если поток, выполняющий код try или catch, прерывается или уничтожается, блок finally может не выполняться, даже если приложение в целом продолжается.

Однако вы правы в том, что выдается исключение ThreadDeathи я не могу найти много подробностей о том, что кажется противоречивой информацией от Солнца.Это может быть вопрос сам по себе.

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

0 голосов
/ 24 июля 2015

Пробный блок выполняется первым.Catch выполняется, если в блоке try есть исключение, которое необходимо перехватить.Наконец, блок выполняется в обоих случаях независимо от того, есть ли исключение или нет.Если в блоке try есть оператор return, то перед возвратом в блок try выполняется блок finally, а затем в блоке try выполняется return.

0 голосов
/ 24 июня 2010

Если вы замените функции кодом метода, вы получите:

public class Main {

    static int a = 0;

    public static void main(String[] args) {
        try {
            try {
                throw new Exception();
            }
            catch (Exception e) {
                // I catch only the *first* exception thrown   
                System.out.println(a + ": inner catch");
                a++;
                // let's go to the finally block
            }
            finally {
                System.out.println(a + ": finally");
                a++;
                // we go on
            }
            System.out.println("---");
            try {
                throw new Exception();
            }
            finally {
                // executed because at the same level
                System.out.println(a + ": finally");
                a++;
            }
        }
        catch(Exception e) {
            // I catch only the *second* exception thrown
            System.out.println(a + ": outer catch");
            a++;
        }
    }

Первое исключение приводит к выполнению блока catch, затем выполняется первый блок finally. Это не видно на внешнем уровне из-за первого блока catch. Второе исключение перехватывается блоком перехвата на внешнем уровне, но, наконец, выполняется первый элемент, расположенный на внутреннем уровне.

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