Тихо закрыть ресурс с помощью try-with-resources

Можно ли игнорировать исключение, создаваемое при закрытии ресурса с помощью оператора try-with-resources?

Пример:

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) {
      }
    }
  }
}
27
задан Jonathan Leffler 9 February 2014 в 23:02
поделиться

1 ответ

Вы можете использовать шаблон декоратора, чтобы тихо закрыть ресурс:

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

Я лично не фанат получающегося синтаксиса, но, возможно, это работает для вас:

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

Вы можете добиться большего успеха, если хотите ограничиться работой с интерфейсами и использовать класс динамического прокси:

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

Тогда предположим, что у вас есть:

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 и без других зависимостей.

19
ответ дан 28 November 2019 в 05:11
поделиться
Другие вопросы по тегам:

Похожие вопросы: