跟我学(Effective Java 2)第7条:避免使用终结方法

第7条:避免使用终结方法

终结方法(finalize)通常是不可预测的,也是很危险的,一般情况下也是不必要的。使用终结方法会导致行为不稳定、降低性能,以及可移植性的问题。虽然终结方法也有可用之处,但是还是应该避免使用它。

终结方法的坏处:

及时的执行终结方法正是垃圾回收算法的主要功能,不同的JVM在执行终结方法的时候的表现大相径庭,如果程序依赖于终结方法被执行的时间点,那么这个程序的行为在不同的JVM中运行的表现会截然不同,一个程序你在测试用的JVM上运行正常可以在顾客的JVM平台上根本无法运行,所以运用时尤为注意。

注意:不该用终结方法来更新重要的持久状态(入数据库操作)。

如果并不确定是否应该避免使用终结方法的时候,这里还有一种值得考虑的情形,如果未被捕获的异常在终结过程中被抛出,那么这种异常可以被忽略,并且对该对象的终结过程也会终止。

未被捕获的异常会使对象处于被破坏的状态,如果另一个线程企图使用这种被破坏的状态,那么则可能发生任何不确定的行为。终结方法还会造成非常严重的性能损失,用终结方法创建和销毁对象会比正常方法要慢很多。

如果类中的对象封闭的资源确实需要被终止,那么应该提供一个显示的终止方法,并且要求客户端在每个实例不再有用的时候调用这个方法,值得提及的一个细节是,该实例必须要记录下自己是否已经被终止 了:显式的终止方法必须在一个私有域中记录下“该对象已经不再有效”。如果这些方法是在对象已经被终止之后被调用,其他的方法就必须检查这个域,并抛出IllegalStateException。

显示的终结方法通常与try-finally结构相结合起来使用,以确保及时的终止。在finally子句中调用显示的终止方法,可以保证即使在使用对象的时候异常抛出,该方法也会执行。

终结方法的好处:

第一种是当对象的所有者忘记调用前面建议的显式终结方法的时候,终结方法可以充当安全网,虽然这样做并不能保证终结方法能被及时的调用,但是在客户端无法通过调用显式的终结方法来正常结束操作的情况下,晚一点释放总比不释放的好。但是如果终结方法发现资源还未被终止,应该在日志中记录一条警告,因为这表明客户端代码中的一个bug,应该得到修复。

第二种合理用途与对象的本地对等体(natvie peer)有关。因为本地对等体不是一个普通的对象,所以垃圾回收器并不知道它,当它的java对等体被回收的时候,它却不会被回收。在本地对等体并不拥有关键资源的前提下,终结方法正是执行这项任务的最合适工具,如果本地对等体拥有必须被及时终止的资源,那么此类就应该具有一个显式的终止方法,终止方法应该完成所有必要的工作以便释放掉关键的资源,终止方法既可以是本地方法,也可以调用本地方法。

如果子类实现者覆盖了超类的终结方法,但是忘了手工调用超类的终结方法,那么超类的终结方法永远也不会被调用到。要防范这样的子类是有可能的,代价就是为每个将被终结的对象创建一个附加的对象,不是把终结方法放在要求终结的类中,而是把终结的方法放在一个匿名的类中,该匿名类的唯一用途就是终结它的外围实例,该匿名类的单个实例被称为终结方法守卫者(finalizer guardian),外围类的每个实例都会创建这样一个守卫者,外围实例在它的私有实例域中保存着一个对其终结方法守卫者的引用,因此终结方法守卫者与外围实例可以同时启动终结过程。当守卫者被终结的时候,它执行外围实例所期望的终结行为,就好像它的终结方法是外围对象上的一个方法一样。

总之,除非是作为安全网,或者是为了终止非关键的本地资源,否则不要使用终结方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值