首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用try-with-resources静默关闭资源

使用try-with-resources静默关闭资源
EN

Stack Overflow用户
提问于 2011-07-31 21:16:43
回答 4查看 12.9K关注 0票数 37

是否可以忽略使用try-with-resources语句关闭资源时抛出的异常?

示例:

代码语言:javascript
复制
class MyResource implements AutoCloseable{
  @Override
  public void close() throws Exception {
    throw new Exception("Could not close");
  }  
  public void read() throws Exception{      
  }
}

//this method prints an exception "Could not close"
//I want to ignore it
public static void test(){
  try(MyResource r = new MyResource()){
    r.read();
  } catch (Exception e) {
    System.out.println("Exception: " + e.getMessage());
  }
}

或者我应该继续在finally中关闭?

代码语言:javascript
复制
public static void test2(){
  MyResource r = null;
  try {
     r.read();
  }
  finally{
    if(r!=null){
      try {
        r.close();
      } catch (Exception ignore) {
      }
    }
  }
}
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2011-07-31 22:49:19

我在硬币开发邮件列表上找到了答案:http://mail.openjdk.java.net/pipermail/coin-dev/2009-April/001503.html

5.可以安全地忽略close方法的某些故障(例如,关闭已打开以进行读取的文件)。该构造是否提供了此功能?

不是的。虽然这个功能看起来很吸引人,但它是否值得增加复杂性还不清楚。作为一个实际问题,这些“无害的异常”很少发生,所以如果这些异常被忽略,程序将不会更健壮。如果你觉得你必须忽略它们,有一个变通方法,但它不是很好:

代码语言:javascript
复制
static void copy(String src, String dest) throws IOException {
    boolean done = false;
    try (InputStream in = new FileInputStream(src)) {
        try(OutputStream out = new FileOutputStream(dest)) {
            byte[] buf = new byte[8192];
            int n;
            while ((n = in.read(buf)) >= 0)
                out.write(buf, 0, n);
        }
        done = true;
    } catch(IOException e) {
        if (!done)
            throw e;
    }
}
票数 29
EN

Stack Overflow用户

发布于 2011-07-31 21:27:53

你可以在这里使用一个装饰器模式来悄悄地关闭资源:

代码语言:javascript
复制
public class QuietResource<T extends AutoCloseable> implements AutoCloseable{
    T resource;
    public QuietResource(T resource){
        this.resource = resource;
    }
    public T get(){
        return resource;
    }
    @Override
    public void close() {
        try {
            resource.close();
        }catch(Exception e){
            // suppress exception
        }
    }  
}

我个人并不喜欢由此产生的语法,但这可能对您有效:

代码语言:javascript
复制
public static void test(){
    try(QuietResource<MyResource> qr = new QuietResource<>(new MyResource())){
        MyResource r = qr.get();
        r.read();
    } catch (Exception e) {
        System.out.println("Exception: " + e.getMessage());
    }
}

如果您愿意将自己限制在处理接口并利用动态代理类,那么您可以做得更好:

代码语言:javascript
复制
public class QuietResource<T> implements InvocationHandler {

    private T resource;

    @SuppressWarnings("unchecked")
    public static <V extends AutoCloseable> V asQuiet(V resource){
        return (V) Proxy.newProxyInstance(
                resource.getClass().getClassLoader(),
                resource.getClass().getInterfaces(),
                new QuietResource<V>(resource));
    }

    public QuietResource(T resource){
        this.resource = resource;
    }

    @Override
    public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
        if(m.getName().equals("close")){
            try {
                return m.invoke(resource, args);
            }catch(Exception e){
                System.out.println("Suppressed exception with message: " + e.getCause().getMessage());
                // suppress exception
                return null;
            }
        }
        return m.invoke(resource, args);
    }
}

然后假设你有:

代码语言:javascript
复制
public interface MyReader extends AutoCloseable{
    int read();
}

使用实际的资源类:

代码语言:javascript
复制
public class MyResource implements MyReader {

    public void close() throws Exception{
        throw new Exception("ha!");
    }

    public int read(){
        return 0;
    }
}

调用语法将如下所示:

代码语言:javascript
复制
public static void test(){
    try(MyReader r = QuietResource.asQuiet(new MyResource())){
        r.read();
    } catch (Exception e) {
        System.out.println("Exception: " + e.getMessage());
    }
}

如果您想要开始包含库,比如AOP enablers,那么您可以做得更好。然而,这些解决方案将与JDK7一起开箱即用,并且没有其他依赖项。

票数 23
EN

Stack Overflow用户

发布于 2011-07-31 21:55:14

这是一种解决方案:

代码语言:javascript
复制
    boolean ok=false;
    try(MyResource r = new MyResource())
    {
        r.read();
        ok=true;
    }
    catch (Exception e)
    {
        if(ok)
            ; // ignore
        else
            // e.printStackTrace();
            throw e;
    }

如果ok==true和我们得到了一个异常,它肯定来自close()

如果为ok==false,则e来自read()或构造函数。close()仍然会被调用,并且可能抛出e2,但e2无论如何都会被禁止。

无需经过这样的分析,代码的可读性非常好。直观地说,如果是ok==true,我们真正的工作就完成了,我们并不关心在那之后会发生什么关于资源的错误。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6889697

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档