使用Java7强制试用资源
我有一个实现AutoCloseable的类,打算与Java7的新的try with resources构造一起使用。但是,我无法找到一种方法来保证我的类的用户使用try-with资源。如果这种情况不发生,那么我的班级将无法自我关闭,糟糕的事情将会发生。有没有任何方法——语言构造或其他方式——来实施这一点?即使能够检测到我是否在try-with-resources块中,以便在不在的情况下抛出异常,也将是一件好事(尽管编译时构造更可取)使用Java7强制试用资源,java,try-with-resources,enforcement,Java,Try With Resources,Enforcement,我有一个实现AutoCloseable的类,打算与Java7的新的try with resources构造一起使用。但是,我无法找到一种方法来保证我的类的用户使用try-with资源。如果这种情况不发生,那么我的班级将无法自我关闭,糟糕的事情将会发生。有没有任何方法——语言构造或其他方式——来实施这一点?即使能够检测到我是否在try-with-resources块中,以便在不在的情况下抛出异常,也将是一件好事(尽管编译时构造更可取) 谢谢 不幸的是,没有办法保护自己不受用户愚蠢行为的影响 您可以
谢谢 不幸的是,没有办法保护自己不受用户愚蠢行为的影响 您可以实现调用
close
的方法;通过这种方式,您可以确保资源至少在对象被垃圾收集时关闭,即使您不知道何时(或是否)发生这种情况
如果您可以对项目的使用方式进行限制,您可能可以使用面向方面的编程强制执行某些策略,但这样您就不再真正使用Java了。不,不可能,如果您继续打开文件或数据库连接,而不关闭它们,同样的坏事也会发生 如果可以在一个方法调用的范围内使用和分配合理的资源,则可以在每次调用api时打开/关闭,如果没有,则只需详细记录行为即可
您的类可能还注册了一个关闭钩子,这样您至少可以在jvm宕机时关闭资源,但我认为这对于库来说是一个糟糕的做法。如果您真的关心资源管理,那么使用回调习惯用法是最安全的方法。您不公开集合,而是一个允许最终用户处理集合中项目的API:
public interface Callback<T> {
void handle(T item);
}
public class SuperVitalVault {
public void all(Callback<Precious> callback) {
try (...) {
for (Precious i : ...) {
callback.handle(i);
}
}
}
}
如果不想定义自己的回调接口,可以使用Guava的函数
或谓词
,但请注意,它违反了Guava建立的语义:
函数的实例通常被期望是引用透明的——没有副作用——并且与equals一致,也就是说,a.equals(b)意味着Function.apply(a).equals(Function.apply(b))
谓词实例通常被认为是无副作用的,并且与equals一致
用户想要手动管理
关闭类,而不是通过资源尝试自动关闭类,这是什么?创建一个调用close
的finalize
方法可以解决您的问题吗?不幸的是,finalize
不能保证被调用。GC可能会决定不调用它。事实上,我想,finalize
的不可靠性可能是引入资源试用的原因。总比什么都不调用好,而且,也不能保证你的用户必须在你的类获得GCD之前调用close
。这就是关键所在——我正试图找出如何实现这种保证。如果我能强迫他们使用try with resources,那么我就得到了保证。在java中,使用Object.finalize()是非常不鼓励的。除非你知道自己在做什么,并且没有其他选择;)@戴维霍夫曼:我想你误解了什么。依靠GC调用finalize可能是不可取的(也是有理由的),但在某些情况下,实际实现finalize方法是防止资源泄漏的唯一选择。我同意@jarnbjo,但是我会让我的api的客户端死掉,并让他们知道api的误用,而不是让他们有不确定的行为。你错了。作为防止资源泄漏的最后一种可能,在完成相应的包装器实例时,文件和网络或数据库连接都将关闭。没有理由不为自己的目的使用相同的实现模式。感谢@jarnbjo的澄清。但我的想法是,如果你一直打开资源而不关闭它们,那么你就有漏洞了。我认为不管怎样,尽早发现漏洞总比晚一点好,如果您以某种方式保留对未关闭对象的引用,那么将不会调用finalize meethod。如果您依赖于GC,那么根据运行程序的ram和GC tunning的数量,您可能会有不确定的行为
try (...) {
for (Precious i : ...) {
if (callback.handle(i)) break;
}
}