【问题标题】:Force try-with-resources Java 7强制 try-with-resources Java 7
【发布时间】:2013-06-30 02:34:12
【问题描述】:

我有一个实现 AutoCloseable 的类,旨在与 Java 7 的新 try-with-resources 构造一起使用。但是,我想不出一种方法来保证我的班级的用户使用 try-with-resources。如果这不发生,那么我的班级将无法自行关闭,并且会发生不好的事情。有什么方法——语言结构或其他方式——来强制执行吗?甚至能够检测我是否在 try-with-resources 块中,这样如果不是的话我可以抛出异常(尽管编译时构造会更好)。

谢谢!

【问题讨论】:

  • 用户想要手动管理 closeing 您的课程,而不是使用 try-with-resources 自动管理?创建一个名为close 的finalize 方法可以解决您的问题吗?
  • 不幸的是,finalize 不能保证被调用。 GC 可能决定不调用它。
  • 其实我猜想finalize的不可靠可能是引入try-with-resources的原因。
  • 总比没有好,并且不能保证您的用户必须在您的课程上调用close,然后才能获得GCed。
  • 这就是重点——我正试图弄清楚如何实现这样的保证。如果我可以强迫他们使用 try-with-resources,那么我就能得到保证。

标签: java try-with-resources enforcement


【解决方案1】:

如果您真的关心资源管理,那么使用回调惯用语是最安全的方法。您不公开集合,而是公开允许最终用户处理集合中项目的 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);
      }
    }
  }
}

如果您想支持提前退出,您可以更改Callback.handle(T) 以返回boolean:

    try (...) {
      for (Precious i : ...) {
        if (callback.handle(i)) break;
      }
    }

如果你不想定义自己的回调接口,可以使用Guava的Function&lt;T, Boolean&gt;或Predicate&lt;T&gt;,但是注意它违反了Guava建立的语义:

Function 的实例通常被期望是引用透明的——没有副作用——并且与 equals 一致,即 a.equals(b) 意味着 function.apply(a).equals(function.apply (b))。

Predicate 的实例通常被认为是无副作用的并且与 equals 一致。

【讨论】:

    【解决方案2】:

    不,没有办法,如果你一直打开文件或数据库连接而不关闭它们,同样的坏事也会发生......

    如果可以在一个方法调用的范围内使用和丢弃合理的资源,您可以在每次调用您的 api 时打开/关闭,如果没有,那么只需详细记录该行为即可。

    你的类也可能注册一个关闭钩子,这样你至少可以在 jvm 出现故障时关闭你的资源,但无论如何我认为这对库来说是一种不好的做法。

    【讨论】:

    • 你错了。当最终确定各自的包装器实例时,文件和网络或数据库连接都将关闭,这是防止资源泄漏的最后一种可能性。没有充分的理由不为自己的目的使用相同的实现模式。
    • 感谢@jarnbjo 的澄清。不过,我的想法是,如果您继续打开资源而不关闭它们,那么您就有泄漏。我认为最好还是早点看到泄漏,如果您以某种方式保留对未关闭对象的引用,那么将不会调用 finalize 方法。如果您依赖 GC,则可能会出现不确定的行为,具体取决于运行程序的 ram 和 gc 调整量
    【解决方案3】:

    不幸的是,没有办法保护自己免受用户愚蠢的影响。

    可以实现finalize方法调用close;这样,您可以确保至少在对象被垃圾回收时资源已关闭,即使您不知道何时(或是否)发生这种情况。

    如果您可以限制项目的使用方式,您也许可以使用面向方面的编程来强制执行一些策略,但是您不再真正使用 Java。

    【讨论】:

    • 在 java 中强烈建议不要使用 Object.finalize()。
    • 除非你知道自己在做什么并且别无选择;)
    • @DavidHofmann:我认为你误解了一些东西。可能(并且有理由)不鼓励依赖 GC 调用 finalize,但实际上 实现 finalize 方法在某些情况下是防止资源泄漏的唯一选择。
    • 我同意@jarnbjo,但是我会让我的 api 的客户快速死亡并让他们了解 api 的误用,而不是让他们有非确定性的行为。
    猜你喜欢
    • 1970-01-01
    • 2021-08-03
    • 1970-01-01
    • 2013-07-21
    • 1970-01-01
    • 2013-07-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多