Какова точка окончательного блока?

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

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

и

try {
}
catch() {
}

x = 3;

изменить: в .NET 2.0?


так

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

является поистине эквивалентным?

Ответ 1

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

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

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

Ответ 2

Ну, во-первых, если вы ВОЗВРАЩАЕТСЯ внутри блока try, то, наконец, все равно будет выполняться, но код, указанный ниже в блоке try-catch-finally, не будет.

Ответ 3

В Java:

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

Ответ 4

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

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

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

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

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

Ответ 5

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

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

Они делают, наконец, блоки превосходными для закрытия дескрипторов файлов или сокетов.

Ответ 6

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

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

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

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

Ответ 7

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

Ответ 8

@iAn и @mats:

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

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();  
}

Ответ 9

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

Ответ 10

Предполагается, что блок finally выполнит, поймал ли вы исключение или нет. См. Пример Try/Catch/finally

Ответ 11

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

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

У Microsoft есть страница справки try-finally для С#

Ответ 12

Блок 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();

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

Ответ 13

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

Ответ 14

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

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

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

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 {}, второе эффективно возвращает), но всегда аккуратно и аккуратно очищается.

Ответ 15

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

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

Я предполагаю, что он похож на .NET?

Ответ 16

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

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

Да, если вы вернетесь из try{}, finally все еще работает. Но это хорошая практика? Похоже, что гинастика может вернуть goto обратно. Почему бы не подождать и вернуться после блока? Все, что делает TG45, это добавляет две или три строки в ваш код.