Close resource quietly using try-with-resources

后端 未结 3 1509
佛祖请我去吃肉
佛祖请我去吃肉 2020-12-05 02:36

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

Example:

class MyResource implements Au         


        
3条回答
  •  野趣味
    野趣味 (楼主)
    2020-12-05 02:55

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

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

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

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

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

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

    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.

提交回复
热议问题