在java中,是否有一种方法可以确保在finally块中调用多个方法



所以我有一个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.

相关内容

最新更新