【问题标题】:What is the best way to emulate try-with-resources in Java 6?在 Java 6 中模拟 try-with-resources 的最佳方法是什么?
【发布时间】:2013-10-30 02:57:01
【问题描述】:

事实证明,几乎没有人正确关闭 Java 中的资源。程序员要么根本不使用try-finally 块,要么只将resource.close() 放在finally 中,这也是不正确的(因为close() 中的Throwable 可以从try 块中隐藏Throwable)。有时他们会放一些像IOUtils.closeQuietly() 这样的东西,只对InputStream 是正确的,但对OutputStream 是不正确的。 try-with-resources 解决了所有这些问题,但仍有大量项目使用 Java 6 编写。

在 Java 6 中模拟 try-with-resources 的最佳方法是什么?现在我用Guava Closer,总比没有好,但还是比try-with-resources丑多了。此外,还有一种称为贷款模式的模式,但 Java 中缺少 lambda 使得这种模式非常麻烦。有没有更好的办法?

【问题讨论】:

  • 使用 Java 7 编译器?
  • Guava Closer 似乎与 Java 6 一样优雅。
  • 我无法使用 Java 7 编译器
  • 仅供参考,IOUtils.closeQuietly 在较新版本的commons-io 中是为Closable 接口定义的。所以你可以用它关闭你想要的东西(不仅仅是流)。 commons.apache.org/proper/commons-io/javadocs/api-2.4/org/…

标签: java try-with-resources


【解决方案1】:

我找到了一个很好的替代 try-with-resources。它使用带有注释处理的Lombok 库:

 @Cleanup InputStream in = new FileInputStream(args[0]);
 @Cleanup OutputStream out = new FileOutputStream(args[1]);
 byte[] b = new byte[10000];
 while (true) {
   int r = in.read(b);
   if (r == -1) break;
   out.write(b, 0, r);
 }

但是,它不能正确处理异常。这个bug已经1年多了,还没有关闭:https://code.google.com/p/projectlombok/issues/detail?id=384

【讨论】:

    【解决方案2】:

    虽然匿名类比较冗长,但在java领域还是可以接受的

        new TryWithResource<InputStream>(){
            protected InputStream init() throws Exception {
                return new FileInputStream("abc.txt");
            }
            protected void use(InputStream input) throws Exception{
                input.read();
            }
        };
    
    ----
    
    abstract class TryWithResource<R>
    {
        abstract protected R init() throws Exception;
        abstract protected void use(R resource) throws Exception;
    
        // caution: invoking virtual methods in constructor!
        TryWithResource() throws Exception
        {
            // ... code before
            R r = init();
            use(r);
            // ... code after
        }
    }
    

    【讨论】:

    • 收盘在哪里?
    • 错了,如果use抛出异常那么流就不会被关闭。无论如何,您都需要包装一个 try/finally 块,因此您的解决方案只是为同一工作提供更多代码。
    • code before/after 涉及 try/finally。我认为这对于任何对这个问题感兴趣的人来说都是不言而喻的。
    【解决方案3】:

    如果您对 IOUtils.closeQuietly 的唯一问题是它忽略了 OutputStreams 上的异常,那么您可以简单地在它们上调用 close(),或者创建您自己的实用程序类来自动区别对待这两者,如下所示:

    public static void close(Closeable resource)
    {
        try
        {
            resource.close();
        }
        catch(Exception e)
        {
            //swallow exception
        }
    }
    
    public static void close(OutputStream o)
    {
        //throw any exceptions
        o.close();
    }
    

    在所有常见情况下,将在编译时选择正确的重载方法,但如果您将OutputStreams 传递为Closeables,那么您必须更改它以执行动态instanceof 检查确保OutputStreams 总是抛出异常。

    【讨论】:

    • 正确处理清理异常所需的代码在没有 try-with-resources 的情况下是非常讨厌的,因为如果 try 块成功,此类异常应该传播,但如果失败则被抑制。跨度>
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-07-18
    • 2017-08-03
    • 2014-09-23
    • 2013-07-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多