在try / catch / finally中“finally”的目的是什么
语法将从语言变为语言,但这是一个普遍的问题。
这有什么区别….
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.");
我一直看到它被使用,所以我认为有一个很好的理由最终使用,但我无法弄清楚它是如何只是在语句之后放置代码,因为它仍然会运行。
有没有一个场景最终没有运行?
在你的例子中,它并没有产生很大的不同。
想象一下:
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之后的任何内容。 但是, finally块仍将运行 。
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");
这实际上取决于 – 其他一些答案有很好的理由使用Finally
块。 但我认为最好的理由是因为你正在进行exception处理 。 你在Finally
块中做的事情通常涉及清理资源以确保适当的继续,无论是否抛出exception – 对我来说仍然是exception处理的一部分,至少是“尝试某事”操作的一部分。
恕我直言, Finally
范围强调了这样一个事实,即它的代码包含在exception情况下值得特别注意的东西。
最后阻止被保证被罚款。 因此,在您的示例中,两种情况的结果看起来都相同。 但是如果你使用return
或者throw
你的catch块,你可以看到有什么区别。
最后应该用于需要完成的所有事情,以保持系统的一致性。 这通常意味着释放资源
无论抛出什么exception,最终都会被执行。 在以下情况下,它应该用于释放资源:
- 完成连接
- 关闭文件处理程序
- 免费记忆
- 关闭数据库连接
让我举一个完整的例子。 想象一下,您正在通过网络发送消息。 在伪代码中:
// 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
的exception时,例如, MethodNotFound
。 在第一种情况下,将调用方法finalizes_connection()
,而在第二种情况下,它将不会。
通过多个程序自然地建立连接。 那么在其他程序的MethodNotFound
exception的情况下会发生什么? 在第一种情况下,您的程序将完成连接和其他程序,它会很高兴。 在第二种情况下,另一个程序可以永远等待您的响应。 如果其他程序每次只能接收一个连接怎么办? 你刚刚窃听了另一个程序。
这也适用于您打开的文件,而其他程序无法打开以供阅读(在Windows中)。 对于内存,它永远不会被释放,现在你有内存泄漏。
最后运行try和catch。 它确保它将运行,但它不是100%保证它会[某些错误停止执行代码]
try块需要至少一个catch或者finally.after执行所有catch块后,finally块将被执行。你可以添加你需要的任何逻辑,最终应该完成。
最后使用它来处理程序崩溃是一个很好的做法。 最终将永远运行。如果函数退出try catch块内部,或者在try或catch中抛出另一个错误,则finally仍将执行。 您不会使用finally语句获得该function。
我不知道C#,但Java-ish语言中finally
块的目的是确保放弃系统资源,尤其是在垃圾收集不规则的情况下。 这对所有人来说都是一样的原则。 考虑一下这个块
InputStream is = new FileInputStream("foo.txt"); OutputStream os = new FileOutputStream("D:/nonexistent/directory/bar.txt"); // Throws a FileNotFoundException.
变量is
成功创建,并占用系统资源。 进程一次只能使用固定数量的文件句柄。 永远不会创建变量os
,并抛出exception,并向调用者冒泡。 在此过程中,超出范围,并有资格进行垃圾回收。
但是,垃圾收集永远不会发生,或者它们可能会在未来的某个无限期发生。 因此,系统资源可能永远不会被释放。 这可能是昂贵的,或者如果程序发生足够的话可能会使程序崩溃。 所以, finally
块被放入Java。 其他语言也有类似的结构。 在C ++中,确定性地调用析构函数。 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人使用Jakarta Commons-IO的IOUtils.closeQuietly()
方法来替换块:
} finally { IOUtils.closeQuietly(is); IOUtils.closeQuietly(os); }
但Java 7引入了更好的解决方案:尝试使用资源。 C#4可能首先出现类似的东西,微软的速度比Snoracle更快。
try ( is = new FileInputStream("foo.txt"), os = new FileOutputStream("D:/nonexistent/directory/bar.txt") ) { // work... }
终于总是运行。 终于就像捕手一样从不错过任何东西。 在你提到的例子中,是的,最后不会添加任何值。 但最后通常用于处置/释放资源。