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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/477399/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 12:33:38  来源:igfitidea点击:

Does Java support RAII/deterministic destruction?

javaraii

提问by j_random_hacker

It's been at least 5 years since I worked with Java, and back then, any time you wanted to allocate an object that needed cleaning up (e.g. sockets, DB handles), you had to remember to add a finallyblock and call the cleanup method in there.

我使用 Java 已经至少 5 年了,那时,任何时候你想分配一个需要清理的对象(例如套接字、DB 句柄),你必须记住添加一个finally块并调用清理方法那里。

By contrast, in C++ (or other languages where object lifetimes are deterministic, e.g. Perl), the class implementor would define a destructor function that performs the cleanup whenever an object of that class goes out of scope. The advantage of this approach is that the user of the object can't forget to clean it up -- the destructor gets called automatically, even if an exception is thrown. This approach goes by the fairly awful name of RAII -- "Resource Acquisition Is Initialisation".

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

It's been my experience that doing things "the RAII way" has saved me a lot of mental overhead in terms of not having to worry about whether and when resource deallocations occur. We are considering using Java for a medium-sized project, and I'm wondering if some sort of deterministic destruction is among the many new features added to the language since I last looked at it. (I'm hopeful as my complaint that "Java has no RAII" was rebuked on this thread, but so far I haven't been able to find any details by googling.)

根据我的经验,“以 RAII 方式”做事为我节省了大量的精神开销,无需担心是否以及何时发生资源释放。我们正在考虑将 Java 用于一个中型项目,我想知道自从我上次查看该语言以来添加到该语言的许多新功能中是否存在某种确定性破坏。(我充满希望,因为我的抱怨“Java 没有 RAII”在这个线程上受到了指责,但到目前为止我还没有通过谷歌搜索找到任何细节。)

So if someone could point me to some introductory material on how to go about this in Java that would be great!

因此,如果有人可以向我指出一些有关如何在 Java 中进行此操作的介绍性材料,那就太好了!

采纳答案by Jon Skeet

EDIT: The answer below was written in early 2009, when Java 7 was very much still in flux.

编辑:下面的答案写于 2009 年初,当时 Java 7 仍在不断变化。

While Java still doesn't provide guarantees around finalization timing, it didgain a feature like C#'s usingstatement: the try-with-resources statement.

虽然 Java 仍然没有提供关于终结时间的保证,但它确实获得了一个类似于 C#using语句的特性:try-with-resources 语句



No, Java hasn't changed at all in that respect. You still need to use try/finally.

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

There's been discussion of adding the equivalent of C#'s "using" statement (which is syntactic sugar over try/finally) to Java, but I don't think that's going to be part of Java 7 any more. (Most of the language improvements seem to have been dropped.)

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

It's worth understanding that there are reasons why deterministic destruction hasn't been implemented in Java and .NET in the form of a reference-counted garbage collector, by the way - that a) impacts performance and b) fails with circular references. Brian Harry wrote a detailed emailabout this - it's about .NET and it's rather old, but it's well worth a close read.

值得理解的是,在 Java 和 .NET 中没有以引用计数垃圾收集器的形式实现确定性破坏是有原因的,顺便说一下 - a) 影响性能 b) 循环引用失败。Brian Harry 写了一封关于此的详细电子邮件- 它是关于 .NET 的,而且它很旧,但非常值得仔细阅读。

回答by philsquared

There is a pattern that helps here. It's not as nice as destructor based RAII but it does mean that the resource clean-up can be moved to the library (so you can't forget to call it).

有一种模式可以在这里提供帮助。它不如基于析构函数的 RAII 好,但它确实意味着可以将资源清理移动到库中(因此您不能忘记调用它)。

It's called Execute Around, and has been discussed here before.

它称为Execute Around,之前已在此处讨论过

Interestingly I see Jon Skeet chimed in on that thread, but he didn't mention it here - shame on you Jon - missed an opportunity for some rep points there!

有趣的是,我看到 Jon Skeet 在该线程中插话,但他没有在这里提到它 - 对你的耻辱 Jon - 错过了在那里获得一些代表点的机会!

BTW, while I'm glad Brian Harry (see Jon's comment, again) went to the lengths of writing the email that he did - and it obviously did reflect a lot of thought that went into the process - and I'm glad we did get "using" out of it in C# - I don't agree with all his conclusions. In particular, I don't see why, if we can have using, we can't have a way to mark a type as behaving that way without "using". Of course it constrains the usage - but so does "using" - and most of the time it's exactly what you want. The trouble with "using" is that the client code still has to remember to use it. With C++ style RAII it's a property of the type. An arguably bigger problem with "using", or more accurately with the Dispose idiom, is that it's a lot more complicated and error prone than most people realise to get right - mostly because of the potential for objects to be brought back from the dead.

顺便说一句,虽然我很高兴布赖恩·哈里(再次参见乔恩的评论)不遗余力地写了他所做的电子邮件 - 显然它确实反映了这个过程中的很多想法 - 我很高兴我们做到了在 C# 中“使用”它 - 我不同意他的所有结论。特别是,我不明白为什么,如果我们可以使用,我们就无法在没有“使用”的情况下将类型标记为行为方式。当然,它限制了使用——但“使用”也是如此——而且大多数时候它正是你想要的。“使用”的麻烦在于客户端代码仍然必须记住使用它。对于 C++ 风格的 RAII,它是该类型的一个属性。“使用”的一个可以说更大的问题,或者更准确地说是处置成语,它是

回答by Jay Stramel

Nope. There is no facility for allocating Objects on the stack. Every Object is allocated on the heap and can outlive whatever block it was initialized in. Or it may be collected mid-block, depending on the vagaries of the all mighty Garbage Collector.

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

If you're working on the server, you might want to check out Java EE. It has nothing to do with RAII, but it does have a decent system for managing the life cycles of expensive objects like DB connections. Java EE 5 is actually pretty nice to work with for a lot of problem spaces.

如果您在服务器上工作,您可能需要查看Java EE。它与 RAII 无关,但它确实有一个不错的系统来管理昂贵对象(如数据库连接)的生命周期。Java EE 5 实际上非常适合用于处理许多问题空间。

回答by Peter Lawrey

The approach I take is to use a layered product (sometime a simple static method) which takes care of the resource allocation. You don't want this sort of resource allocation littering your program.

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

There are plenty of libraries which do this. It not something you should have to worry about in most cases.

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