Помимо синтаксиса, в чем разница между
try {
}
catch() {
}
finally {
x = 3;
}
и
try {
}
catch() {
}
x = 3;
изменить: в .NET 2.0?
так
try {
throw something maybe
x = 3
}
catch (...) {
x = 3
}
поведенчески эквивалентно?
Чтобы выбрать лучший ответ, я думаю, вам нужно уточнить, действительно ли блоки try / catch пусты или нет. Как указано в одном из ответов, семантика одинакова, если блоки try / catch пусты, в противном случае разные ответы касаются семантических различий.
Я согласен с предыдущими комментариями, вам необходимо уточнить реальный язык и серьезно изучить полученные ответы. Обновленные ответы либо неверны, либо неполны.





Таким образом, вы можете очистить любые открытые соединения и т. д., Инициализированные в блоке try. Если вы открыли соединение, а затем возникло исключение, это исключение не будет закрыто должным образом. Для этого типа сценария и нужен блок finally.
В Java:
Наконец, всегда вызывается, независимо от того, правильно ли было перехвачено исключение в catch () или действительно ли у вас вообще есть перехват.
Всегда очень сильное слово
Зависит от языка, поскольку могут быть небольшие семантические различия, но идея состоит в том, что он будет выполняться (почти) всегда, даже если код в блоке try выдал исключение.
Во втором примере, если код в блоке catch возвращается или завершается, x = 3 не будет выполняться. Во первых так и будет.
В платформе .NET в некоторых случаях выполнение блока finally не происходит: Исключения безопасности, приостановка потоков, выключение компьютера :) и т. д.
Я бы добавил к списку методов, предотвращающих выполнение блока finally, вызов Environment.Exit.
Ну, во-первых, если вы вернетесь в свой блок try, finally все равно будет работать, но код, указанный под блоком try-catch-finally, не будет.
Ты прав. Это хороший ответ, но я полагаю, что он не дает прямого ответа на поставленный вопрос. Может быть, это означает, что мне следовало задать вопрос получше :)
Здесь все правы. Полагаю, я был сокращен. Я заметил, что первые ответы получают все положительные голоса. ;-)
Это было мое подозрение, и я ценю подтверждение. Хотя он краток, он дает правильный ответ.
Блок finally должен выполняться независимо от того, поймали ли вы исключение или нет. См. Попробуйте / Поймайте / Наконец пример
В случае, если try и catch пусты, разницы нет. В противном случае вы можете быть уверены, что окончательный вариант будет выполнен.
Если вы, например, создадите новое исключение в своем блоке catch (повторно выбросите), то присвоение будет выполнено только в том случае, если оно находится в блоке finally.
Обычно finally используется для очистки после себя (закрытие соединений с БД, дескрипторов файлов и т.п.).
Вы никогда не должны использовать управляющие операторы (return, break, continue) в finally, так как это может быть кошмаром обслуживания и поэтому считается плохой практикой.
Блок finally всегда будет вызываться (ну, на самом деле не всегда ...), даже если генерируется исключение или достигается оператор возврата (хотя это может зависеть от языка). Это способ очистки, который, как вы знаете, всегда будет называться.
Мне всегда нравилась ежедневная статья о wtf, на которую вы ссылались, - особенно один из комментариев, в котором говорится, что нам нужна magicFairyFinally, которая гарантированно работает даже без питания!
@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();
Однако помните, что что-либо внутри, наконец, не может работать. Представьте, что вы получили сигнал прерывания, вылетели окна или пропало электричество. В конечном итоге полагаться на критически важный для бизнеса код - это плохо.
пожалуйста, определите язык, поскольку это подразумевается в вашем ответе, но не указано.
Переполнение стека также приведет к тому, что блок finally не будет выполняться.
Я думаю, что первый пример кода неверен (в C#) - переменные, объявленные в блоке try, имеют область видимости нет в блоках catch или finally. Я попробовал это в тестовом приложении C# и получил ошибку времени компиляции в ссылке на блок finally: «Имя 'stream' не существует в текущем контексте».
Любой код в finally запускается даже в случае необработанного исключения. Обычно код finally используется для очистки локальных объявлений неуправляемого кода с помощью .dispose ().
попробуйте поймать наконец-то - довольно важная конструкция. Вы можете быть уверены, что даже в случае возникновения исключения код в блоке finally будет выполнен. При обращении с внешними ресурсами очень важно их высвободить. Сборка мусора не сделает этого за вас. Наконец, у вас не должно быть операторов возвращаться или исключений. Это возможно, но это плохая практика и может привести к непредсказуемым результатам.
Если вы попробуете этот пример:
try {
return 0;
} finally {
return 2;
}
Результат будет 2 :)
Сравнение с другими языками: Вернуться из наконец
Имейте в виду, что блок Final не всегда выполняется. Переполнение стека (не каламбур) приведет к тому, что блок finally не будет выполняться.
Результат будет 2 на Java. В C# этот код нельзя скомпилировать.
Наконец, блоки позволяют вам, как разработчику, привести себя в порядок после себя, независимо от действий предыдущего кода в блоке try {}, в котором возникли ошибки, и если другие указали на это, это в основном подпадает под действие освобождения ресурсов - закрытие указатели / сокеты / наборы результатов, возвращающие соединения в пул и т. д.
@mats очень верен в том, что всегда есть вероятность "серьезных" сбоев - блоки finally не должны включать критически важный код, который всегда должен выполняться транзакционно внутри попытки {}
@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 {}, второй эффективно возвращает), но всегда аккуратно и аккуратно проясняется.
Есть несколько вещей, которые делают блок finally полезным:
Эти блоки make finally отлично подходят для закрытия файловых дескрипторов или сокетов.
@iAn и @mats:
Я бы не стал "срывать" что-либо в finally {}, что было "настроено" в 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();
}
Обратите внимание: линия throw(e); //rewrites stack trace отличается от throw; //re-throws the original exception.
В Java вы используете его для всего, что хотите выполнить, независимо от того, использовали ли вы «возврат», просто выполнили блок try или было перехвачено исключение.
Например, закрытие сеанса базы данных или JMS-соединения или освобождение некоторого ресурса ОС.
Я предполагаю, что это похоже на .NET?
Это вопрос Старый, но меня это всегда беспокоило (не зря я нашел его здесь). Я прочитал все ответы, и мне кажется, что никто не продумал их до конца.
Это не ответ. Я действительно думаю, что в finally нет ничего хорошего, возможно, поэтому он не существовал в языках программирования до «недавнего времени». Большинство примеров, в которых указывается, что stream.close() может вызывать исключения нулевой ссылки, поэтому вам все равно придется проверить, является ли он нулевым.
Да, если вы вернетесь из try{}, finally все равно будет работать. Но разве это хорошая практика? Похоже на гинастику, с таким же успехом можно было бы вернуть goto. Почему бы не подождать и не вернуться после блока? Все, что делает finally {}, - это добавляет в ваш код две или три строки.
Вы можете указать язык программирования. Поведение будет зависеть от языка.