Java是否支持RAII /确定性破坏?

时间:2009-01-25 08:44:27

标签: java raii

自从我使用Java以来​​已经至少5年了,当时,只要你想分配一个需要清理的对象(例如套接字,数据库句柄),你就必须记得添加一个{{1}阻塞并调用那里的清理方法。

相比之下,在C ++(或其他对象生命周期是确定性的语言,例如Perl)中,类实现者将定义一个析构函数,只要该类的对象超出范围,该函数就会执行清理。这种方法的优点是对象的用户不会忘记清理它 - 即使抛出异常,也会自动调用析构函数。 RAII这个名称非常糟糕 - “资源获取是初始化”。

根据我的经验,做“RAII方式”的事情在不必担心是否以及何时发生资源解除分配方面为我节省了大量精神开销。我们正在考虑将Java用于一个中等规模的项目,我想知道自从我上次查看它以来,语言中添加的许多新功能是否存在某种确定性破坏。 (我希望因为我的抱怨“Java没有RAII”被指责on this thread,但到目前为止我还没能通过谷歌搜索找到任何细节。)

所以,如果有人能够指出一些关于如何在Java中实现这一目标的介绍性材料,那就太棒了!

4 个答案:

答案 0 :(得分:25)

编辑:下面的答案写于2009年初,当时Java 7仍然处于不稳定状态。

虽然Java仍无法提供有关终结时间的保证,但 获得了类似C#using语句的功能:try-with-resources statement


不,Java在这方面根本没有改变。你仍然需要使用try / finally。

有人讨论过将相当于C#的“using”语句(这是语法糖而不是try / finally)添加到Java中,但我不认为这将成为Java 7的一部分。 (大多数语言改进似乎已被删除。)

值得理解的是,为什么在Java和.NET中没有以引用计数的垃圾收集器的形式实现确定性破坏,顺便说一句,a)影响性能,b)因循环引用而失败。 Brian Harry写了一篇关于这个的detailed email - 它是关于.NET的,而且相当古老,但是值得仔细阅读。

答案 1 :(得分:9)

有一种模式可以帮到这里。它不如基于析构函数的RAII那么好,但它确实意味着资源清理可以移动到库中(所以你不能忘记调用它)。

它被称为Execute Around, and has been discussed here before

有趣的是,我看到Jon Skeet在这个帖子中插话,但是他没有在这里提到它 - 羞辱你Jon - 错过了那里的一些代表的机会!

顺便说一句,虽然我很高兴Brian Harry(再次看到Jon的评论)写了他写的电子邮件的长度 - 这显然反映了很多进入这个过程的想法 - 我是很高兴我们在C#中得到了“使用” - 我不同意他的所有结论。特别是,我不明白为什么,如果我们可以使用,我们就没有办法将类型标记为没有“使用”的行为。当然它限制了使用 - 但“使用”也是如此 - 而且大部分时间它都是你想要的。 “使用”的麻烦在于客户端代码仍然需要记住使用它。使用C ++风格的RAII,它是该类型的属性。 “使用”或者更准确地说使用Dispose惯用语这个可以说是更大的问题是,它比大多数人认为要做到的更复杂和容易出错 - 主要是因为物体可能从死亡中被带回来。

答案 2 :(得分:2)

不。没有用于在堆栈上分配对象的工具。每个对象都在堆上分配,并且可以比它初始化的任何块寿命更长。或者它可以在块中间收集,这取决于所有强大的垃圾收集器的变幻莫测。

如果您正在使用服务器,则可能需要查看Java EE。它与RAII无关,但它确实有一个很好的系统来管理像DB连接这样的昂贵对象的生命周期。 Java EE 5实际上很适合处理很多问题空间。

答案 3 :(得分:0)

我采用的方法是使用分层产品(有时是简单的静态方法)来处理资源分配。你不希望这种资源分配乱丢你的程序。

有很多图书馆可以做到这一点。在大多数情况下,这不是你应该担心的事情。