使用try-with-resources静静地关闭资源

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

例:

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()); } } 

或者我应该继续关闭?

 public static void test2(){ MyResource r = null; try { r.read(); } finally{ if(r!=null){ try { r.close(); } catch (Exception ignore) { } } } } 

我在coin-dev邮件列表中找到了这个答案: http : //mail.openjdk.java.net/pipermail/coin-dev/2009-April/001503.html

5.可以安全地忽略close方法的某些失败(例如,关闭打开以供读取的文件)。 构造是否提供了这个?

不会。虽然这个function似乎很有吸引力,但不清楚它是否值得增加复杂性。 实际上,这些“无害的exception”很少发生,所以如果忽略这些exception,程序就不会更加健壮。 如果您觉得必须忽略它们,那么有一种解决方法,但它并不漂亮:

 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; } } 

您可以在此处使用装饰器模式来安静地关闭资源:

 public class QuietResource 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 } } } 

我个人并不喜欢结果语法,但也许这适合你:

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

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

 public class QuietResource implements InvocationHandler { private T resource; @SuppressWarnings("unchecked") public static  V asQuiet(V resource){ return (V) Proxy.newProxyInstance( resource.getClass().getClassLoader(), resource.getClass().getInterfaces(), new QuietResource(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); } } 

然后假设你有:

 public interface MyReader extends AutoCloseable{ int read(); } 

使用实际资源类:

 public class MyResource implements MyReader { public void close() throws Exception{ throw new Exception("ha!"); } public int read(){ return 0; } } 

调用语法如下:

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

如果要开始包含库(如AOP启用程序),则可以做得更好。 但是,这些解决方案将与JDK7一起开箱即用,没有其他依赖关系。

这是一个解决方案:

  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并且我们得到了一个exception,它肯定来自close()

如果ok==false ,则e来自read()或构造函数。 仍然会调用close()并抛出e2 ,但无论如何都会抑制e2。

代码非常易读,无需经过此类分析。 直观地说,如果ok==true ,我们的实际工作已经完成,我们并不关心资源之后的错误。