5

所以我有一个尝试/ finally块。我需要在finally块中执行一些方法。但是,这些方法中的每一个都会引发异常。有没有办法确保所有这些方法都被调用(或试图)没有嵌套finally块?在java中,有没有办法确保在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 
     } 
    }    
} 

是否有一个更优雅的方式来做到这一点?

+3

你可以将它们解压缩到清理方法中。 – Reimeus

+0

'有没有办法确保所有这些方法被调用(或企图)**没有嵌套finally块**?' –

回答

2

标准(工作)的方式来正确的资源管理中的Java(的原则也适用于其他语言)是:

Resource resource = acquire(resource); 
try { 
    use(resource); 
} finally { 
    resource.release(); 
} 

或者使用当前的快捷方式(用聪明的一个额外位)版本的Java SE:

try (Resource resource = acquire(resource)) { 
    use(resource); 
} 

(正如Joe K指出的那样,您可能需要打包资源以确认Java语言所依赖的特定接口。)

两个资源,您只需使用两次成语:7

Resource resource = acquire(resource); 
try { 
    SubResource sub = resource.acquire(); 
    try { 
     use(sub); 
    } finally { 
     sub.release(); 
    } 
} finally { 
    resource.release(); 
} 

而且在Java SE:

try (
    Resource resource = acquire(resource); 
    SubResource sub = resource.acquire() 
) { 
    use(resource, sub); 
} 

新的语言功能的真正伟大的优点是资源处理是写出来的时候往往不会破碎。

您可能会有更复杂的异常处理。例如,您不希望将低级异常(例如IOException)丢到适当的应用程序中 - 您可能想要打包RuntimeException的某个子类型。这可以通过使用“执行周围”惯用语(参见this excellent question)以Java的典型冗长性进行分解。从Java SE 8开始,还会有更短的语法和随机不同的语义。

with(new ResourceSubAction() { public void use(Resource resource, SubResource sub) { 
    ... use resource, sub ... 
}}); 
0

一般来说,没有办法解决这个问题。你需要多个finally块。

但是,我不想评论您的具体代码,无论这是否是合适的设计。它看起来很奇怪。

+0

是的,如果你能看到业务逻辑,代码更有意义。为了简洁起见,我把它留下了。 – sangfroid

0

我没有办法害怕。关闭io资源时有类似的模式。例如,当关闭文件时,你会怎样抛出一个IOException?通常你只需要忽略它。由于这是一个反模式,所以他们在Java 7中引入了try-with语法。对于您的示例,尽管我认为没有其他选择。也许把每一个最后都纳入它自己的方法来使其更清晰

0

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

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

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

2

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

0

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

0
deleteTableSilently(table1);  
deleteTableSilently(table2);  
deleteTableSilently(table3); 


deleteTableSilently() 
    try 
     deleteTable() 
    catch whatever 
     log.error(); 
0

考虑使用java.util.concurrent的框架 - 如果你的代码每次调用作为一个单独的可赎回(命名或匿名的),你可以使用ExecutorService.invokeAll。

相关问题