在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() ,而在第二种情况下,它将不会。

通过多个程序自然地建立连接。 那么在其他程序的MethodNotFoundexception的情况下会发生什么? 在第一种情况下,您的程序将完成连接和其他程序,它会很高兴。 在第二种情况下,另一个程序可以永远等待您的响应。 如果其他程序每次只能接收一个连接怎么办? 你刚刚窃听了另一个程序。

这也适用于您打开的文件,而其他程序无法打开以供阅读(在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... } 

终于总是运行。 终于就像捕手一样从不错过任何东西。 在你提到的例子中,是的,最后不会添加任何值。 但最后通常用于处置/释放资源。