[英]Can my AutoCloseable.close() implementation detect a potential exception?
在实现AutoCloseable
以使用Java 7 try-with-resources语句时,我想知道try块中是否存在异常。 例如:
class C implements AutoCloseable {
@Override
public void close() {
if (exceptionOccurred)
something();
else
somethingElse();
}
}
为了说明这一点:
try (C c = new C()) {
// This should cause a call to "something()"
if (something)
throw new RuntimeException();
// This should cause a call to "somethingElse()"
else
;
}
现在,从了解try-with-resources语句如何转换为字节码 ,我想这是不可能的。 但是有没有(可靠!)技巧通过instrumentation / reflection /一些未记录的编译器功能,允许我从AutoCloseable.close()
访问上面的RuntimeException
?
注意:我是一名API设计师,我无法控制API使用者的资源尝试代码。 因此,必须在AutoCloseable
站点上完成实现
执行此操作的常规方法是在try块的末尾显式调用。 例如:
try (CustomTransaction transaction = ...) {
// Do something which might throw an exception...
transaction.commitOnClose();
}
然后在close
,你要么根据是否调用commitOnClose()
而中止事务或提交它。
它不是自动的,但它实现起来非常简单 - 而且阅读起来非常简单。
我一直在努力解决这个问题。 我不喜欢Jon Skeet的回答,因为开发人员(即我)可能会意外忘记调用commitOnClose()
。 我想要一种方法让开发人员在离开代码块时被强制调用commit()或rollback()。
Lambda和已检查的异常并不能很好地协同工作,所以正确的解决方案有点令人费解,但最终我和我的同事想出了一段允许你这样工作的代码:
TransactionEnforcer.DbResult<String> result = transactionEnforcer.execute(db -> {
try {
db.someFunctionThatThrowsACheckedException();
} catch (TheException e) {
return failure("fallback value");
}
return success(db.getAFancyValue());
});
result.ifPresent(v -> System.out.println(v));
注意如何返回值,可以检查代码是否成功,并且java的代码路径返回检查强制您始终明确是否应该提交代码。
它使用以下代码实现:
package nl.knaw.huygens.timbuctoo.database;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Supplier;
public class TransactionEnforcer {
private final Supplier<DbClass> dbClassFactory;
public TransactionEnforcer(Supplier<DbClass> dbClassFactory) {
this.dbClassFactory = dbClassFactory;
}
public <U> DbResult<U> execute(Function<DbClass, DbResult<U>> actions) {
DbClass db = dbClassFactory.get();
try {
DbResult<U> result = actions.apply(db);
if (result.isSuccess()) {
db.close(true);
} else {
db.close(false);
}
return result;
} catch (RuntimeException e) {
db.close(false);
throw e;
}
}
public static class DbResult<T> {
private final Optional<T> value;
private final boolean success;
private DbResult(T value, boolean success) {
this.value = Optional.of(value);
this.success = success;
}
public static <T> DbResult<T> success(T value) {
return new DbResult<T>(value, true);
}
public static <T> DbResult<T> success() {
return new DbResult<T>(null, true);
}
public static <T> DbResult<T> failure(T value) {
return new DbResult<T>(value, false);
}
public static <T> DbResult<T> failure() {
return new DbResult<T>(null, false);
}
public boolean isSuccess() {
return success;
}
public Optional<T> getValue() {
return value;
}
}
}
(我将DbClass作为练习留给读者)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.