Какой смысл в блоке finally? - PullRequest
       105

Какой смысл в блоке finally?

28 голосов
/ 09 сентября 2008

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

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

и

try {
}
catch() {
}

x = 3;

редактировать: в .NET 2.0?


так

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

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

Ответы [ 15 ]

37 голосов
/ 09 сентября 2008

Ну, во-первых, если вы ВОЗВРАТИТЕ внутри своего блока try, finally все равно будет работать, но код, указанный под блоком try-catch-finally, не будет.

33 голосов
/ 09 сентября 2008

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

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

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

10 голосов
/ 09 сентября 2008

В Java:

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

9 голосов
/ 09 сентября 2008

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

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

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

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

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

6 голосов
/ 09 сентября 2008

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

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

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

2 голосов
/ 09 сентября 2008

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

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

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

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

1 голос
/ 09 сентября 2008

@ iAn и @mats:

Я бы не стал "срывать" что-либо в finally {}, которое было "настроено" в 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();  
}
1 голос
/ 09 сентября 2008

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

0 голосов
/ 28 сентября 2008

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

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

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

0 голосов
/ 09 сентября 2008

Наконец, блоки позволяют вам, как разработчику, привести себя в порядок, независимо от действий предыдущего кода в блоке 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 {}, второй эффективно возвращает), но всегда аккуратно и аккуратно очищается.

...