Java 对于清理代码(比如关闭流),finally块真的是必要的吗?

Java 对于清理代码(比如关闭流),finally块真的是必要的吗?,java,exception-handling,try-catch-finally,Java,Exception Handling,Try Catch Finally,我很困惑,为什么我需要像在finally块中关闭流那样放置清理代码 我已经读到,finally块中的代码将在任何情况下运行(无论是否存在异常);在finally块运行之后,该方法的其余部分继续 我的问题是:如果该方法的其余部分必须继续,那么为什么不将清理代码放在函数中的try/catch块之后 以防遇到意外异常(未捕获和处理) 在finally块运行之后,方法的其余部分继续 只有在没有发现异常的情况下,这才是正确的。如果在try块内发生异常,将执行catch块(如果此异常有一个),将执行fina

我很困惑,为什么我需要像在
finally
块中关闭流那样放置清理代码

我已经读到,
finally
块中的代码将在任何情况下运行(无论是否存在异常);在
finally
块运行之后,该方法的其余部分继续


我的问题是:如果该方法的其余部分必须继续,那么为什么不将清理代码放在函数中的try/catch块之后

以防遇到意外异常(未捕获和处理)

在finally块运行之后,方法的其余部分继续

只有在没有发现异常的情况下,这才是正确的。如果在try块内发生异常,将执行catch块(如果此异常有一个),将执行finally块,然后如果catch块进一步抛出异常,将控制权交给方法的调用方,而不在此方法中运行任何进一步的代码


编辑:阐明catch当然必须返回,而不仅仅是吃掉异常。

如果抛出未捕获的异常,finally块将始终运行,但方法中的其余代码将被跳过


因此,如果将清理代码放在finally块之后,如果出现异常,它将不会被调用。

如果出现
异常,即执行try块,那么,请放心,
finally
块也将被执行。这只是一个保护选项,而不是不可靠地假设方法的其余部分将被执行

我的问题是,;如果该方法的其余部分必须继续,那么为什么不将干净的代码放在函数的try/catch块之后呢

可以这样做,但必须通过传递需要关闭的对象引用(非java资源),在finally块中再次调用此函数。因为如果此函数不是finally block,并且如果发生任何异常,则将跳过整个方法,而不关闭非java资源

您还可以使用java7功能->。非java资源将自动关闭。您不需要使用finally块

如果该方法的其余部分必须继续,那么为什么我不将 函数中try/catch块之后的清理代码

因为清理代码与您的
try
操作相关,该操作尝试打开资源等,从逻辑上讲,它应该是
final
子句的一部分,因为它是与
try
相关的最后一个操作
例如,由于在返回之前必须进行一些处理,因此在100行之后关闭文件或连接是没有意义的。
你得到结果了。没有例外,释放资源。最好在
finally
中执行,这样您的代码就会更干净,因为它总是被执行

我的问题是,;如果该方法的其余部分必须继续,那么为什么不将清理代码放在函数中的try/catch块之后呢

基本上是这样的:

InputStream is = ...
try {
   // use stream
} catch (IOException ex) {
   // report / recover
}
is.close();
但是,如果
//use stream
部分抛出一个不同的(例如未选中的)异常,会发生什么?还是
//报告/恢复
代码?无论哪种情况,
close()
调用都不会发生。(如果这些块中有
break
return
语句怎么办?)

从理论上讲,以这种方式实施是可能的。问题在于确保代码始终(即始终)运行。要做到这一点,就很难不捕获一大堆不应该捕获的异常。。。如果你真的抓到了,你就无法正常处理

总之,
最后
是更好的解决方案

  • 这比正确处理情况所需的卷积要简单,而且
  • 这比典型的半心半意的尝试更可靠
如果您可以使用新的Java7“try with resources”表单,其中
finally
会自动处理,那么它就更简单/更可靠了


我想补充一点,您对执行
finally
子句的时间的描述有点不准确。实际上,无论try块如何终止,都会执行
finally
块,包括:

  • try
    块从末端脱落时
  • 当它抛出异常时。。。无论是否在此级别捕获异常,或
  • 当执行
    返回
    继续
    中断

实际上,
finally
块不执行的唯一情况是
try
块调用
System.exit()
或JVM崩溃。(或者如果它进入一个无限循环…

也许这里有一个小小的误解(或者是我自己误解了)。无论方法是否在异常条件下存在,都将运行finally块,例如

 try {
      throw new Exception();
 }
 finally {
      // Block of code will be called before the method exits as exception is thrown
 }
请注意,该规则几乎没有例外,例如:

 try {
      System.exit(-1);
 }
 finally {
      // Block of code will be called before the method exits as exception is thrown
 }

这是一种(相当危险的)情况,程序将在不执行finally块的情况下退出。

finally块对人和编译器都有好处

不仅要注意编译器,还要注意阅读代码的人。
如果清理部分位于finally块中,那么编辑代码将非常容易

最终块将100%确定执行try/catch是否将完全执行

因此,如果您想释放系统资源,请在finally块中编写代码。
还有方法的返回语句。

来吧。。。显然是一个错误的陈述!try-catch块后面的代码呢?实际上,忘记了“catch忽略或正确处理异常”。对不起,这是唯一有用的话。干净利落,精力充沛。不仅总是跑步,而且从不跑两次。如果最后没有
的话,问题会更糟。
@MarkoTopolnik-是的,尽管有很多