Java 自动关闭ish方法,但仅在捕获时运行

Java 自动关闭ish方法,但仅在捕获时运行,java,Java,我希望有两个不同的方法在catch和final块中运行。我找到了可自动关闭的接口,但我需要一些东西,以防出现异常。 比如: SomeService service = CreateService().andOpenTransaction() try { service.doSomeMessyThingsInsideDB(); } catch (Exception e) { service.rollbackTransaction(); throw e; } finally


我希望有两个不同的方法在
catch
final
块中运行。我找到了可自动关闭的
接口,但我需要一些东西,以防出现异常。
比如:

SomeService service = CreateService().andOpenTransaction()

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

有没有办法让它更简单?正如我所说,我熟悉AutoCloseable,但它只在finally block方面对我有帮助。我仍然不能在捕捉器内使用它。

您说您熟悉自动关闭功能,但您没有使用它。 您是否考虑过使用
try with resources
语句

您的代码可以简化为:

try (SomeService service = CreateService().andOpenTransaction()) {
    service.doSomeMessyThingsInsideDB();
} catch(exception e){
    service.rollbackTransaction();
    throw e;
}
Oracle在这方面做得很好,包括示例

注意:try with resources语句可以像普通的try语句一样具有catch和finally块。在try with resources语句中,任何catch或finally块都会在声明的资源关闭后运行

回答你的问题,这是最简单的。
如果您的类没有实现
Closeable
,那么您可以实现它,或者使用
最终
好的,您可以定义自己的接口,然后使用一些
静态
运行方法:

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;
         }
     }
}
你可以这样称呼它:

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(); }
});
execute(
    service::doSomeMessyThingsInsideDB, 
    service::rollbackTransaction, 
    service::closeConnection
);
但你看,还是很乱

您甚至可以在
SomeService
中实现这个
接口
,但是您受到限制,
run()
方法将始终调用
dosomeMessynthingsInsidedB()


另一种方法(但仍然类似)是使用Java8并创建一个helper functional
接口

public interface ThrowingRunnable {
   void run() throws Exception;
}
然后是某个地方的
静态
方法:

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)
,它“注册”您的
onFinally
方法,以便在到达
时调用

这可以这样称呼:

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(); }
});
execute(
    service::doSomeMessyThingsInsideDB, 
    service::rollbackTransaction, 
    service::closeConnection
);
第一步:处理异常

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

/** 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);
            });
}
/**引发运行时异常*/
作废流程(可调用的工作、消费者onFail){
试一试{
work.call();
}捕获(例外e){
onFail(e);
}
}
试试(SomeService=CreateService().和opentransaction()){
进程(()->service.doSomeMessyngsInsidedB(),
e->{
service.rollbackTransaction();
抛出新的非法状态异常(e);
});
}
这不是很令人满意,但同样集成了AutoCloseable,可能给出的用例太少

第二步:自动关闭

void processAutoClosing(供应商服务工厂、,
可调用的工作,用户onFail){
try(SV service=serviceFactory.get()){
过程(工作、失败);
}
}
进程自动关闭(…);

没有这样的接口,当捕捉到异常时,就只有自动关闭了。您可以用lambdas编写一个函数。为什么要从服务外部开始这个事务?恐怕我不能在catch块中使用“service”变量。这是我的问题。如果编译器允许我按照您编写的方式编写代码,我将不会有任何问题。我只是在寻找最好的模式:)看起来“尝试资源”在这种情况下不适合我。如果没有人能在一天结束前找到答案,我会将你的答案标记为“答案”。你的解决方案也缺少
和OpenTransaction()
部分。@M.Prokhorov谢谢,我在方法执行之前添加了它。看起来很酷,但有点过分了。事实上,你回答了我的问题,所以要点还是要告诉你的:)@Arkadiusz欢迎你,我添加了另一种方法,通过使用Java8函数接口来实现你的愿望。这仍然是一个有点,但较少过度工程