Какова цель "наконец" в try/catch/наконец
Синтаксис изменится с языка на язык, но это общий вопрос.
В чем разница между этим....
try
{
Console.WriteLine("Executing the try statement.");
throw new NullReferenceException();
}
catch (NullReferenceException e)
{
Console.WriteLine("{0} Caught exception #1.", e);
}
finally
{
Console.WriteLine("Executing finally block.");
}
и это....
try
{
Console.WriteLine("Executing the try statement.");
throw new NullReferenceException();
}
catch (NullReferenceException e)
{
Console.WriteLine("{0} Caught exception #1.", e);
}
Console.WriteLine("Executing finally block.");
Я продолжаю видеть, что он используется, поэтому я предполагаю, что есть веская причина для использования, наконец, но я не могу понять, как он отличается от того, как просто поставить код после утверждения, поскольку он все равно будет работать.
Есть ли когда-нибудь сценарий, который, наконец, не запускается?
Ответы
Ответ 1
В вашем примере это не имеет большого значения.
Изобразите это, хотя:
try
{
Console.WriteLine("Executing the try statement.");
throw new NullReferenceException();
}
catch (SomeOtherException e)
{
Console.WriteLine("{0} Caught exception #1.", e);
}
finally
{
Console.WriteLine("Executing finally block.");
}
Console.WriteLine("Executing stuff after try/catch/finally.");
В этом случае catch
не поймает ошибку, так что ничего после цельной try/catch/, наконец, никогда не будет достигнуто. Тем не менее, блок finally все равно будет работать.
Ответ 2
try
{
throw new Exception("Error!");
}
catch (Exception ex)
{
throw new Exception(ex, "Rethrowing!");
}
finally
{
// Will still run even through the catch kicked us out of the procedure
}
Console.WriteLine("Doesn't execute anymore because catch threw exception");
Ответ 3
окончательный блок гарантированно должен быть исключен.
Итак, в вашем примере результаты обоих случаев выглядят одинаково.
но если вы используете return
или throw
в своем блоке catch, вы можете увидеть, в чем разница.
Ответ 4
Это действительно зависит - некоторые другие ответы имеют очень веские основания использовать блок Finally
. Но я думаю, что лучшая причина в том, что вы занимаетесь обработкой исключений. Все, что вы делаете в блоке Finally
, как правило, включает очистку ресурсов для обеспечения надлежащего продолжения, независимо от того, было ли исключено исключение - для меня это все еще часть обработки исключений, по крайней мере, часть операции "попробуйте что-то".
IMHO область Finally
подчеркивает тот факт, что ее код содержит материалы, которые заслуживают особого внимания в случае исключения.
Ответ 5
Наконец, нужно использовать все, что нужно сделать, чтобы поддерживать целостность системы. Обычно это означает, что ресурсы релиза
Наконец, всегда выполняется, независимо от того, какое исключение было выбрано. Он должен использоваться для освобождения ресурсов в следующих случаях:
- Завершить соединение
- Закройте обработчик файлов
- Свободная память
- Закройте соединение с базой данных
Позвольте мне привести полный пример. Представьте, что вы отправляете сообщения через сеть. В псевдокоде:
// With finally | //Without finally
try{ | try{
send_message() | send_message()
} catch(NetworkError){ | } catch(NetworkError){
deal_with_exception() | deal_with_exception()
} finally { | }
finalizes_connection() | finalizes_connection()
} |
Единственное отличие обоих кодов заключается в том, что то, что удерживается в блоке try
, вызывает исключение, которое не является NetworkError
, например, MethodNotFound
. В первом случае будет вызван метод finalizes_connection()
, а во втором - нет.
Соединение, естественно, выполняется через несколько программ. Итак, что происходит в случае исключения MethodNotFound
для другой программы? В первом случае ваша программа завершит соединение и другую программу, и она будет счастлива. Во втором случае другая программа может ждать вашего ответа навсегда. Что делать, если другая программа может получать только одно соединение за раз? Вы просто прослушали другую программу.
Это также относится к файлу, например, который вы открыли, и другие программы не смогут открывать для чтения (в Windows). И для памяти он никогда не выпускается, и теперь у вас есть утечка памяти.
Ответ 6
наконец запускается как для try, так и для catch. Он гарантирует, что он будет работать, но на 100% он не гарантирует, что [некоторые ошибки остановят выполнение кода]
Ответ 7
попробуйте блокировать, по крайней мере, один улов или, наконец, после завершения всех блоков catch, блок finally будет выполнен. Вы можете добавить любую логику, в которой вы нуждаетесь, что должно быть сделано в конечном итоге.
Ответ 8
Хорошая практика использования, наконец, для обработки сбоев программы. наконец, всегда будет работать. Если функция выходит из блока catch try или другая ошибка возникает либо в try, либо в catch, окончательно все равно будет выполняться. Вы не получите эту функциональность, не используя выражение finally.
Ответ 9
Я не знаю С#, но цель блока finally
на Java-иш-языках - обеспечить отказ системных ресурсов, особенно если сборка мусора является нерегулярной. Это тот же принцип для всех. Рассмотрим блок
InputStream is = new FileInputStream("foo.txt");
OutputStream os = new FileOutputStream("D:/nonexistent/directory/bar.txt");
// Throws a FileNotFoundException.
Переменная is
создается успешно и обрабатывает системные ресурсы. Процессы могут использовать только фиксированное количество дескрипторов файлов за раз. Переменная os
никогда не создается, и генерируется исключение, и пузырьки до вызывающего. В процессе is
выходит за пределы области видимости и становится пригодным для сбора мусора.
Однако коллекции мусора никогда не гарантируются, или они могут произойти в какое-то неопределенное время в будущем. Таким образом, системные ресурсы, полученные с помощью is
, никогда не могут быть освобождены. Это может быть дорогостоящим или может привести к сбою программы, если это произойдет достаточно долго. Итак, finally
блоки были помещены в Java. Другие языки имеют похожие конструкции. В С++ деструкторы вызываются детерминистически. Языки LISPy имеют unwind-protect
, но обычно они упаковываются в макросы with-foo
.
В Java 6 и ниже это можно сделать:
try {
is = new FileInputStream("foo.txt");
os = new FileOutputStream("D:/nonexistent/directory/bar.txt");
// work...
} finally {
if (is != null) {
try {
is.close();
} catch (IOException ignored) {}
}
if (os != null) {
try {
os.close();
} catch (IOException ignored) {}
}
}
Вы не можете просто вызвать is.close()
, потому что это может быть брошено, а затем os
никогда не будет закрыто. Вы также должны проверить на null
. Sane people использовали методы Jakarta Commons-IO IOUtils.closeQuietly()
для замены блока:
} finally {
IOUtils.closeQuietly(is);
IOUtils.closeQuietly(os);
}
Но Java 7 представила лучшее решение: try-with-resources. С# 4, вероятно, на первом месте с чем-то похожим, Microsoft быстрее использует поглощение, чем Snoracle.
try (
is = new FileInputStream("foo.txt"),
os = new FileOutputStream("D:/nonexistent/directory/bar.txt")
) {
// work...
}
Ответ 10
наконец, всегда всегда выполняется. наконец, как зрелище, которое никогда не пропускает ничего. В приведенном выше примере да, наконец, не добавляет никакого значения. Но, наконец, обычно используется для удаления/освобождения ресурсов.