首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >AutoCloseable方法,但只在捕获时运行

AutoCloseable方法,但只在捕获时运行
EN

Stack Overflow用户
提问于 2020-02-14 10:50:30
回答 3查看 77关注 0票数 2

我想在catchfinal块中运行两个不同的方法。我已经找到了AutoCloseable接口,但是我只需要在异常情况下触发一些东西。

比如:

代码语言:javascript
复制
SomeService service = CreateService().andOpenTransaction()

try {
    service.doSomeMessyThingsInsideDB();
} catch (Exception e) {
    service.rollbackTransaction();
    throw e;
} finally {
    service.closeConnection();
}

有什么办法让它更简单吗?正如我说的,我熟悉AutoCloseable,但它只帮助我最终阻止。我还是不能在渔获物里面用它。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2020-02-14 11:02:32

您可以定义自己的接口,然后使用一些static runner方法:

代码语言:javascript
复制
public interface ErrorHandlingCloseable extends AutoCloseable {
     void run() throws Exception;
     void onError(Exception e);

     static void execute(ErrorHandlingClosable ehc) throws Exception {
         try(ErrorHandlingClosable temp = ehc) {
             ehc.run();
         } catch(Exception e) {
             ehc.onError(e);
             throw e;
         }
     }
}

然后你就可以这样称呼它:

代码语言:javascript
复制
SomeService service = CreateService().andOpenTransaction();
ErrorHandlingCloseable.execute(new ErrorHandlingCloseable() {
    public void run() throws Exception { service.doSomeMessyThingsInsideDB(); }
    public void onError(Exception e) { service.rollbackTransaction(); }
    public void close() throws Exception { service.closeConnection(); }
});

但你看,还是很乱。

您甚至可以在您的interface中实现这个SomeService,但是这样就限制了run()方法总是调用doSomeMessyThingsInsideDB()

另一种方法(但仍然类似)是使用Java8并创建一个助手函数interface

代码语言:javascript
复制
public interface ThrowingRunnable {
   void run() throws Exception;
}

然后在某个地方使用static方法:

代码语言:javascript
复制
public static void execute(ThrowingRunnable action,
                           ThrowingRunnable onCatch,
                           ThrowingRunnable onFinally) throws Exception {
   try(AutoCloseable ao = onFinally) {
       action.run();
   } catch(Exception e) {
       onCatch.run();
       throw e;
   }
}

有趣的部分可能是:try(AutoCloseable ao = onFinally),它“注册”要在到达finally时调用的onFinally方法。

这样就可以这样称呼它:

代码语言:javascript
复制
execute(
    service::doSomeMessyThingsInsideDB, 
    service::rollbackTransaction, 
    service::closeConnection
);
票数 1
EN

Stack Overflow用户

发布于 2020-02-14 10:57:06

你说你熟悉AutoCloseable,但你不使用它。您考虑过使用try-with-resources语句吗?

您的代码可以简化为:

代码语言:javascript
复制
try (SomeService service = CreateService().andOpenTransaction()) {
    service.doSomeMessyThingsInsideDB();
} catch(exception e){
    service.rollbackTransaction();
    throw e;
}

甲骨文在这方面有很好的文档,包括例子。

Note:具有资源的语句可以有catch并最终阻塞,就像普通try语句一样。在“使用资源的尝试”语句中,在声明的资源被关闭后,将运行任何catch或最终块。

回答您的问题,这是它所能得到的最简单的。如果您的类没有实现Closeable,那么您可以实现它或使用finally

票数 1
EN

Stack Overflow用户

发布于 2020-02-14 11:28:06

第一步:处理异常

显然,您希望在关闭之前处理异常。然后,您需要在一个使用资源进行尝试的内部处理异常。

代码语言:javascript
复制
/** throws RuntimeException */
void process(Callable<Void> work, Consumer<Exception> onFail) {
    try {
        work.call();
    } catch (Exception e) {
        onFail(e);
    }
}

try (SomeService service = CreateService().andOpenTransaction()) {
    process(() -> service.doSomeMessyThingsInsideDB(),
            e -> {
                service.rollbackTransaction();
                throw new IllegalStateException(e);
            });
}

这不是很令人满意,但同样也集成了AutoCloseable,可能会给出太少的用例。

第二步:使用AutoCloseable的

代码语言:javascript
复制
<SV extends AutoCloseable> void processAutoClosing(Supplier<SV> serviceFactory,
                                               Callable<Void> work, Consumer<Exception> onFail) {
try (SV service = serviceFactory.get()) {
    process(work, onFail);
}

}

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

https://stackoverflow.com/questions/60224866

复制
相关文章

相似问题

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