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。

相關問題