Выполняется ли блок finally, даже если вы генерируете новое исключение?

147

В этом коде будет someVarустановлено, даже если выполняется блок catch и выбрасывается второе Exception?

public void someFunction() throws Exception {
    try {
        //CODE HERE
    } catch (Exception e) {
        Log.e(TAG, "", e);
        throw new Exception(e);
    } finally {
        this.someVar= true;
    }
}
Джекс
источник
2
Потому что есть обстоятельства, при которых поведение не соответствует ожиданиям, на что указывает @GaryF
jax
1
Стоит отметить, что последний блок может выполняться не так, как ожидалось, если он генерирует исключение или выполняет возврат.
Питер Лоури,

Ответы:

191

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

  • Поток, выполняющий блок try-catch-finally, убит или прерван
  • Ты используешь System.exit(0);
  • Базовая виртуальная машина уничтожается другим способом
  • Базовое оборудование каким-то образом непригодно

Кроме того, если метод в вашем блоке finally выдает неперехваченное исключение, то после этого ничего не будет выполнено (т.е. исключение будет выброшено, как и в любом другом коде). Очень распространенный случай, когда это происходит java.sql.Connection.close().

В стороне, я предполагаю, что образец кода, который вы использовали, является всего лишь примером, но будьте осторожны, помещая фактическую логику внутри блока finally. Блок finally предназначен для очистки ресурсов (закрытие соединений с БД, освобождение дескрипторов файлов и т. Д.), А не для логики обязательного запуска. Если он должен быть запущен, сделайте это до блока try-catch, вдали от чего-то, что может вызвать исключение, поскольку ваше намерение почти наверняка функционально такое же.

GaryF
источник
4
Что вы имеете в виду, говоря «Поток, выполняющий блок try-catch-finally, [...] прерван»? Возможно, эта документация плохо сформулирована, но Thread.interrupt () не приведет к пропуску блока finally, независимо от того, выброшен ли он из блока try или catch. Означает ли это слово «прерванный» что-то более жестокое, например Thread.stop ()?
Джо Кирни,
@Joe: Да, я думаю, что документ здесь немного нечетко сформулирован и означает общее прерывание активности потока.
GaryF
@GaryF - я думаю, вы цитируете JLS. Формулировка JLS иногда бывает немного странной, но обычно вы обнаружите, что значение странной терминологии четко определено в другом месте документа. JLS - это спецификация, основной целью которой является точность (а не удобочитаемость).
Stephen C
1
@Stephen C - Фактически, это произошло из учебника по JavaSE (на который есть ссылки). Это может быть сформулировано аналогичным образом в JLS, но я не могу найти соответствующую часть. Я ожидал этого в главе 11 (Исключения), главе 14 (Утверждения) или главе 15 (Выражения), но не вижу ничего, что явно относится к прерываниям. Конечно, мне было бы интересно это увидеть.
GaryF
1
@GaryF - Понятно. На самом деле JLS говорит о «нормальном» и «внезапном» завершении операторов, и есть раздел (14.1), который определяет терминологию. Затем поведение finallyопределяется в терминах нормального и внезапного завершения.
Stephen C
10

Да.

См. Документацию :

Блок finally всегда выполняется при выходе из блока try.

Исключения:

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

фроди
источник
2

Наконец, всегда выполняется блок.

public class ExceptionTest {

public static void someFunction(String input) throws Exception {
    try {
        if( input.equals("ABC") ) {
            System.out.println("Matched");
        }
    } catch (Exception e) {
        throw new Exception(e);
    } finally {
        System.out.println("Input Is "+input+" Finally Executed!!!");
    }
}

/**
 * @param args
 */
public static void main(String[] args) {
    // TODO Auto-generated method stub
    try {
        System.out.println("********* Test with VALUE ********* ");
        someFunction("ABC");
        System.out.println("\r\n********* Test with NULL  ********* ");
        someFunction(null);
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

}

Java Попробуйте поймать окончательный блок с помощью Throw

Васантх Умапати
источник
2

Наконец, всегда выполняется, независимо от вашего случая, т.е.

  • попытка поймать окончательно блок
  • бросает

Для непроверенных исключений java не требует обработки ошибок. по этой причине, если непроверенное исключение возникает в блоке finally и для этого не выполняется никакой обработки, то код, написанный ниже этой точки (где возникла ошибка), не будет выполнен.

Поэтому я предлагаю всегда обрабатывать все исключения, независимо от того, отмечен он или нет. Таким образом, вы можете убедиться, что блок кода в finally также выполняется независимо от того, возникает ли непроверенное исключение. у вас есть место в sub-nest catch и finally block, чтобы выполнить необходимую работу.

юг
источник
1

Да. finallyblock выполняется всегда, за исключением случая, когда вы вызываете System.exit (), потому что он останавливает виртуальную машину Java.

Владимир Иванов
источник
Перехватчики завершения работы по-прежнему вызываются после System.exit (), но все существующие несистемные потоки останавливаются.
Питер Лоури,