所以我有一个try/finaly块。我需要在finally块中执行许多方法。但是,这些方法中的每一个都可能引发异常。有没有一种方法可以确保在没有嵌套finally块的情况下调用(或尝试)所有这些方法?
这就是我现在所做的,非常丑陋:
protected void verifyTable() throws IOException {
Configuration configuration = HBaseConfiguration.create();
HTable hTable = null;
try {
hTable = new HTable(configuration, segmentMatchTableName);
//...
//various business logic here
//...
} finally {
try {
try {
if(hTable!=null) {
hTable.close(); //This can throw an IOException
}
} finally {
try {
generalTableHelper.deleteTable(configuration, segmentMatchTableName); //This can throw an IOException
} finally {
try {
generalTableHelper.deleteTable(configuration, wordMatchTableName); //This can throw an IOException
} finally {
generalTableHelper.deleteTable(configuration, haplotypeTableName); //This can throw an IOException
}
}
}
} finally {
HConnectionManager.deleteConnection(configuration, true); //This can throw an IOException
}
}
}
有更优雅的方法吗?
在Java中正确管理资源的标准(工作)方法(该原则也适用于其他语言)是:
Resource resource = acquire(resource);
try {
use(resource);
} finally {
resource.release();
}
或者在当前版本的Java SE:中使用快捷方式(稍微聪明一点)
try (Resource resource = acquire(resource)) {
use(resource);
}
(正如Joe K所指出的,您可能需要包装资源,使其确认Java语言所依赖的特定接口。)
两种资源,你只需两次应用这个成语:
Resource resource = acquire(resource);
try {
SubResource sub = resource.acquire();
try {
use(sub);
} finally {
sub.release();
}
} finally {
resource.release();
}
在Java SE 7:中
try (
Resource resource = acquire(resource);
SubResource sub = resource.acquire()
) {
use(resource, sub);
}
新语言功能真正的巨大优势是,在编写时,资源处理往往会被破坏。
您可能有更复杂的异常处理。例如,您不想将诸如IOException
之类的低级别异常抛出到应用程序本身——您可能想要封装RuntimeException
的某个子类型。这可以通过Java典型的措辞,使用Execute Around习惯用法来解决(请参阅这个优秀的问题)。从Java SE 8开始,还会出现语义随机不同的较短语法。
with(new ResourceSubAction() { public void use(Resource resource, SubResource sub) {
... use resource, sub ...
}});
如果这是Java 7,您可以考虑使用新的try-with-resources构造。您可能需要创建一些基本的AutoCloseable
包装来删除表。
一般来说,这是没有出路的。您需要多个finally块。
然而,我不想评论你的具体代码,无论这是否是一个合适的设计。这看起来确实很奇怪。
恐怕没有办法。关闭io资源时也有类似的模式。例如,当关闭一个文件引发IOException时,你该怎么办?通常你只需要忽略它。由于这有点像反模式,他们在Java7中引入了try-win语法。以你为例,我认为别无选择。也许最终将每个方法放入自己的方法中,使其更清晰
要从finally块调用多个方法,必须确保它们都不抛出——这无论如何都是个好主意,因为从finally区块抛出的任何异常都将覆盖从try/catch抛出的异常或返回值。
最常见的用例是文件或数据库连接,在这种情况下,您可以编写一个"悄悄关闭"方法(或使用现有库中的方法,如Jakarta Commons IO)。如果你需要清理的东西不允许你使用预先存在的方法,你可以编写自己的方法(在你的情况下,deleteTableQuietly()
)。
如果您使用的是JDK-7,您也可以使用"try-with-resources"构造。
您可以创建一个带有execute方法的抽象类Action,并从该类派生出一个类,用于每个要调用的抛出异常的方法,从execute方法调用此方法。然后,您可以创建一个Actions列表,并在列表的元素上循环,在try-filly块中调用它们的execute方法,忽略异常。
deleteTableSilently(table1);
deleteTableSilently(table2);
deleteTableSilently(table3);
deleteTableSilently()
try
deleteTable()
catch whatever
log.error();
考虑使用java.util.courrent框架——如果将每个调用编码为单独的Callable(命名或匿名),则可以使用ExecutorService.invokeAll.