【问题标题】:In java, is there a way to ensure that multiple methods get called in a finally block?在java中,有没有办法确保在finally块中调用多个方法?
【发布时间】:2012-08-31 18:55:49
【问题描述】:

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

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

【问题讨论】:

  • 您可以将它们提取到清理方法中。
  • Is there a way to ensure that all these methods are called (or attempted) **without nested finally blocks**?

标签: java exception exception-handling try-catch-finally try-finally


【解决方案1】:

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

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

【讨论】:

  • 是的,如果你能看到业务逻辑,代码更有意义。为了简洁起见,我把它省略了。
【解决方案2】:

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

【讨论】:

    【解决方案3】:

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

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

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

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

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

        【讨论】:

          【解决方案6】:

          在 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 习惯用法(参见 this excellent question)来消除 Java 的典型冗长性。从 Java SE 8 开始,还会有更短的语法和随机不同的语义。

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

          【讨论】:

            【解决方案7】:
            deleteTableSilently(table1);    
            deleteTableSilently(table2);    
            deleteTableSilently(table3);
            
            
            deleteTableSilently()
                try
                    deleteTable()
                catch whatever
                    log.error();
            

            【讨论】:

              【解决方案8】:

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

              【讨论】:

                猜你喜欢
                • 2010-10-05
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多