Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Close resource quietly using try-with-resources

Is it possible to ignore the exception thrown when a resource is closed using a try-with-resources statement?

Example:

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

Or should I continue to close in a finally instead?

public static void test2(){
  MyResource r = null;
  try {
     r.read();
  }
  finally{
    if(r!=null){
      try {
        r.close();
      } catch (Exception ignore) {
      }
    }
  }
}
like image 330
dogbane Avatar asked Jul 31 '11 13:07

dogbane


People also ask

Does try with resources Auto close?

The Java try with resources construct, AKA Java try-with-resources, is an exception handling mechanism that can automatically close resources like a Java InputStream or a JDBC Connection when you are done with them.

What is the use of try with resources?

The try -with-resources statement is a try statement that declares one or more resources. A resource is an object that must be closed after the program is finished with it. The try -with-resources statement ensures that each resource is closed at the end of the statement. Any object that implements java.

Can we use try with resources without catch and finally?

Yes, It is possible to have a try block without a catch block by using a final block. As we know, a final block will always execute even there is an exception occurred in a try block, except System. exit() it will execute always.

What happens when an exception is thrown from the try with resources?

For try-with-resources, if an exception is thrown in a try block and in a try-with-resources statement, then the method returns the exception thrown in the try block. The exceptions thrown by try-with-resources are suppressed, i.e. we can say that try-with-resources block throws suppressed exceptions.


3 Answers

I found this answered on the coin-dev mailing list: http://mail.openjdk.java.net/pipermail/coin-dev/2009-April/001503.html

5. Some failures of the close method can be safely ignored (e.g., closing a file that was open for read). Does the construct provide for this?

No. While this functionality seems attractive, it is not clear that it's worth the added complexity. As a practical matter these “harmless exceptions” rarely if ever occur, so a program will be no more robust if these exceptions are ignored. If you feel you must ignore them, there is a workaround, but it isn't pretty:

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;     } } 
like image 189
dogbane Avatar answered Sep 19 '22 20:09

dogbane


You could use a decorator pattern here to close the resource quietly:

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

I'm not personally a fan of the resulting syntax, but maybe this works for you:

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

You can do better if you're willing to limit yourself to dealing with interfaces and leverage a Dynamic Proxy Class:

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

Then assuming you have:

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

With an actual resource class:

public class MyResource implements MyReader {

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

    public int read(){
        return 0;
    }
}

Calling syntax would look like:

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

You can do better than this if you want to start including libraries, like AOP enablers. These solutions, however, will work out of the box with JDK7 and no other dependencies.

like image 35
Mark Elliot Avatar answered Sep 20 '22 20:09

Mark Elliot


This is one solution:

    boolean ok=false;
    try(MyResource r = new MyResource())
    {
        r.read();
        ok=true;
    }
    catch (Exception e)
    {
        if(ok)
            ; // ignore
        else
            // e.printStackTrace();
            throw e;
    }

If ok==true and we got an exception, it definitely comes from close().

If ok==false, e comes from read() or constructor. close() will still be called and may throw e2, but e2 will be suppressed anyway.

The code is quite readable without going through such analysis. Intuitively it says, if ok==true, our real work is done, and we don't really care what errors come after that regarding the resource.

like image 22
irreputable Avatar answered Sep 18 '22 20:09

irreputable