5

所以我有一个 try/finally 块。我需要在 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   
        }
    }               
}

有没有更优雅的方法来做到这一点?

4

8 回答 8

2

如果这是 Java 7,您可以考虑使用新的 try-with-resources 构造。您可能需要创建一些基本AutoCloseable的包装来删除表。

于 2012-09-06T21:55:44.963 回答
2

在 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. 这可以使用 Execute Around 成语(参见这个优秀的问题)来解决,因为 Java 的典型冗长性。从 Java SE 8 开始,还会有更短的语法和随机不同的语义。

with(new ResourceSubAction() { public void use(Resource resource, SubResource sub) {
    ... use resource, sub ...
}});
于 2012-09-06T22:14:06.290 回答
0

一般来说,这是没有办法的。您需要多个 finally 块。

但是,我不想评论您的特定代码,无论这是否是适当的设计。它看起来确实很奇怪。

于 2012-09-06T21:47:47.557 回答
0

没有办法我害怕。关闭 io 资源时也有类似的模式。例如,当关闭文件引发 IOException 时,您会怎么做?通常你只需要忽略它。因为这有点像反模式,所以他们在 Java 7 中引入了 try-with 语法。对于您的示例,尽管我认为没有其他选择。也许将每个 finally 放入自己的方法中以使其更清晰

于 2012-09-06T21:55:26.577 回答
0

要从 finally 块调用多个方法,您必须确保它们都不抛出 - 无论如何这是一个好主意,因为从 finally 块抛出的任何异常都将覆盖从 try/catch 抛出的异常或返回值。

最常见的用例是文件或数据库连接,在这种情况下,您编写“安静地关闭”方法(或使用现有库中的一个,例如 Jakarta Commons IO)。如果你需要清理的东西不允许你使用预先存在的方法,你自己写(在你的情况下,deleteTableQuietly())。

如果您使用的是 JDK-7,您还可以使用“ try with resource ”构造。

于 2012-09-06T21:55:34.667 回答
0

您可以使用 execute 方法创建一个抽象类 Action,并从该类派生一个类,用于每个要调用的抛出异常的方法,从 execute 方法调用此方法。然后,您可以创建一个 Action 列表并遍历列表中的元素,在 try finally 块中调用它们的 execute 方法,忽略异常。

于 2012-09-06T21:56:14.950 回答
0
deleteTableSilently(table1);    
deleteTableSilently(table2);    
deleteTableSilently(table3);


deleteTableSilently()
    try
        deleteTable()
    catch whatever
        log.error();
于 2012-09-06T22:27:08.150 回答
0

考虑使用 java.util.concurrent 框架——如果将每个调用编码为单独的 Callable(命名或匿名),则可以使用 ExecutorService.invokeAll。

于 2012-09-06T23:26:14.780 回答