第8条 避免使用终结方法和清理器
-
终结方法(finalizer)通常是不可预测的,也是很危险的,一般情况下是不必要的。使用终结方法会导致行为不稳定,降低性能,以及可移植性问题。
-
不要把finalizer当成是C++中的析构器(destructors)的对应物。
-
终结方法并不一定会被及时的执行,从一个对象变得不可到达开始,,到它的终结方法被执行,,所花费的时间是任意长的。JVM会延迟执行终结方法。
-
Java语言规范不能保证终结方法会被执行,不应该依赖终结方法来更新重要的持久状态。
-
System.gc()
和System.runFinalization()
方法增加了终结方法被执行的机会,但是它们并不保证终结方法一定会被执行。 -
使用终结方法或者清洁器会导致要种的性能损失
-
如果类的对象中封装的资源(例如文件或线程)确实需要终止,只需提实现
AutoCloseable
,提供一个显式的终止方法close()
。并要求该类的客户端在每个实例不再有用的时候调用这个方法。该实例必须记录下自己是否已经被终止了,如果被终止之后再被调用,要抛出异常。 -
终结方法的两种使用场景:
-
当显式终止方法被忘记调用时,终结方法可以充当安全网(safety net)。但是如果终结方法发现资源还未被终止,应该记录日志警告,这表示客户端代码中的bug。
-
对象的本地对等体(native peer),垃圾回收器不会知道它,当它的Java对等体被回收的时候,它不会被回收。
如果本地对等体拥有必须被及时终止的资源, 那么该类就应该有一个显式的终止方法,如前面的
close()
。如果本地对等体并不拥有关键资源,终结方法是执行这项任务最合适的工具。
-
第9条 优先使用try-with-resources
而不是try-finally
-
try-finally
最大的问题是当有多个资源需要关闭的时候,嵌套的时候看起来很丑。并且如果try和finally块中都有异常抛出,通常第二个会掩盖了第一个。 -
使用
try-with-resources
只需要实现AutoCloseable
接口 -
当多个异常抛出的时候, 后续异常会被suppressed, 可以通过
getSuppressed()
-
在Java7中,
try-with-resources
,代码块中使用的资源必须在try中定义,Java9之后可以引入外面的变量Java7:
public void test1() throws Exception { InputStream inputStream1 = new FileInputStream("123"); try (InputStream inputStream2 = inputStream1) { inputStream2.read(); } }
Java9:
public void test2() throws Exception { InputStream inputStream1 = new FileInputStream("123"); InputStream inputStream2 = new FileInputStream("456"); try (inputStream1; inputStream2) { inputStream1.read(); } }
TMS中引用资源的场景还是非常多的。自己见过的主要有连接ftp和temp目录。我们有一些接口后者lts会访问linux目录,对此我们封装了一个类。但是这个类有一个比较严重的问题是里面每调用一个方法都会连接再断开,非常浪费资源,可以把整个类实现AutoClosable,只有初始化和结束的时候连接和断开。另外就是我们的下载和发邮件,会需要先生成一个文件放在temp目录,这一步操作会需要输出流,也可以使用try-with-resources。以后可以将try-with-resources作为一个代码规范
网友评论