В чем смысл блока finally?

синтаксис в сторону, в чем разница между

try {
}
catch() {
}
finally {
    x = 3;
}

и

try {
}
catch() {
}

x = 3;

edit: в .NET 2.0?


так

try {
    throw something maybe
    x = 3
}
catch (...) {
    x = 3
}

эквивалентно ли поведение?

15 ответов


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

во втором примере, если код в блоке catch возвращает или завершает работу, x = 3 не будет выполнен. В первом - да.

в платформе .NET в некоторых случаях выполнение блока finally не происходит: Исключения безопасности, приостановки потоков, выключение компьютера :), п.


Ну, во-первых, если вы вернетесь внутри своего блока try, то finally все равно будет работать, но код, указанный ниже блока try-catch-finally, не будет.


В Java:

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


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

Если вы попробуете это пример:

try {
  return 0;
} finally {
  return 2;
}

результат будет 2:)

сравнение с другими языками: Возвращение Из Finally


есть несколько вещей, которые делают блок finally полезен:

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

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


в случае, если попытка и уловка пусты, нет никакой разницы. В противном случае вы можете быть уверены, что последнее будет выполнено.

Если вы, например, создадите новое исключение в своем catchblock (rethrow), то задание будет выполнено только в том случае, если оно находится в finally-block.

обычно a, наконец, используется для очистки после себя (закрыть DB-соединения, дескрипторы файлов и тому подобное).

вы никогда не должны использовать control-statements (return, перерыв, продолжить) в конце концов, как это может быть кошмар обслуживания и поэтому считается плохой практикой


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


@iAn и @mats:

Я бы не" срывал "ничего в finally {}, что было "настроено" в try {} как правило. Было бы лучше вытащить создание потока за пределы try {}. Если вам нужно обработать исключение в stream create, это можно сделать в большей области.

StreamReader stream = new StreamReader("foo.bar");  
try {
    mySendSomethingToStream(stream);
}
catch(noSomethingToSendException e) {
    //Swallow this    
    logger.error(e.getMessage());
}
catch(anotherTypeOfException e) {
    //More serious, throw this one back
    throw(e);
}
finally {
    stream.close();  
}

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


блок finally должен выполняться независимо от того, поймали ли вы исключение или нет. См.Try / Catch / Finally example


@Ed, возможно, вы думаете о чем-то вроде catch(...) который ловит не указанное исключение в C++.

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

Microsoft имеет страницу попробуйте-наконец для C#


блок finally находится в той же области, что и try/catch, поэтому у вас будет доступ ко всем переменным, определенным внутри.

представьте, что у вас есть обработчик файлов, это разница в том, как он будет написан.

try
{
   StreamReader stream = new StreamReader("foo.bar");
   stream.write("foo");
}
catch(Exception e) { } // ignore for now
finally
{
   stream.close();
}

по сравнению с

StreamReader stream = null;
try
{
    stream = new StreamReader("foo.bar");
    stream.write("foo");
} catch(Exception e) {} // ignore

if (stream != null)
    stream.close();

помните, хотя что-нибудь внутри, наконец, не гарантируется. Представьте, что вы получаете сигнал прерывания, сбои windows или питание пропало. Опираясь на finally для бизнес-критического кода плохой.


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


наконец, блоки позволяют вам, как разработчику, убирать за собой, независимо от действий предшествующего кода в блоке try {}, встречающихся ошибок, и другие указали на это, в основном подпадает под зонтик освобождения ресурсов - закрытие указателей / сокетов / результирующих наборов, возврат соединений в пул и т. д.

@mats очень правильно, что всегда есть потенциал для "жестких" сбоев-наконец, блоки не должны включать критически важный код, который всегда следует делать транзакционно внутри try{}

@mats снова-настоящая красота в том, что она позволяет вам выбрасывать исключения из ваших собственных методов и по-прежнему гарантировать, что вы убираете:

try
{
StreamReader stream = new StreamReader("foo.bar");
mySendSomethingToStream(stream);
}
catch(noSomethingToSendException e) {
    //Swallow this    
    logger.error(e.getMessage());
}
catch(anotherTypeOfException e) {
    //More serious, throw this one back
    throw(e);
}
finally
{
stream.close();
}

таким образом, мы можем поймать много типов исключений, обрабатывать их по-разному (первый позволяет выполнять что-либо за пределами try {}, второй эффективно возвращает), но всегда аккуратно и аккуратно очищается.


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

например, закрытие сеанса базы данных или соединения JMS или освобождение некоторого ресурса ОС.

Я думаю, он похож по .Нет?