2014-10-29 77 views
4

如果你有一些需要運行的清理代碼,無論是否拋出異常,try { ... } finally { ... }就是你需要的。但是如果你想讓這個清理代碼只在發生異常時才運行呢?習慣性的Java「finally」塊只能運行在異常處

一個可能的解決方案是這樣的:

boolean ok = false; 
try { 
    doWork(); 
    ok = true; 
} finally { 
    if (!ok) { 
     doCleanup(); 
    } 
} 

它確實正是我想要的,但我想知道是否有表達的想法更自然的方式。

這種替代不鼓起傳遞:

try { 
    doWork(); 
} catch (Throwable e) { 
    doCleanup(); 
    throw e; // BAD: Cant do this unless the enclosing function is declared to throw Throwable 
} 

我想我能趕上例外,而不是Throwable的,但我不喜歡這個主意,一個非異常拋出將繞過清理代碼。畢竟,即使對於非拋出異常,常規的finally塊仍然運行。

旁白:在C++中,您只需使用一個包羅萬象的塊:

try { 
    doWork(); 
} catch (...) { 
    doCleanup(); 
    throw; 
} 
+0

你第一個選擇應該工作正常。你不需要聲明你正在拋出'Throwable'。 – azurefrog 2014-10-29 21:15:03

回答

6

從Java 7的,這是合法的代碼:

public static void method() { 
    try { 
    // stuff which doesn't declare checked exceptions 
    } catch (Throwable t) { 
    throw t; 
    } 
} 

改進後的語言規則允許這一點,因爲靜態分析可以證明t實際上不會任何檢查的異常。

同樣的,你只需要申報的最低限度的必要檢查的異常:

public static void method() throws IOException { 
    try { 
    throwingMethod(); 
    } catch (Throwable t) { throw t; } 
} 

static void throwingMethod() throws IOException {} 
+0

這很有趣。此外,它似乎在Java 7編譯。 – Radiodef 2014-10-29 21:27:51

+1

因爲它在Java 7中工作,這就是我的目標(對不起,我應該在OP中指定),這是一個複選標記。 – Will 2014-10-29 21:30:04

4

如果你有一個try ...... finally塊,則兩種情況之一適用:

  1. 您對此方法有throws子句,並且try塊可能會引發檢查異常。

有一個catch塊捕獲RuntimeException S和任何檢查的異常:

catch (RuntimeException | YourCheckedException e) { 
    // Cleanup 
    throw e; 
} 
  • 您沒有一個throws子句,並且try塊僅可拋出一個未檢查的異常。
  • Catch RuntimeException,不需要在throws中聲明。

    catch (RuntimeException e) { 
        // Cleanup 
        throw e; 
    } 
    
    +1

    '錯誤'呢?我認爲OP也希望在這些情況下進行清理。 – 2014-10-29 21:20:24

    +1

    我想我可以添加錯誤的多捕獲,但仍然不會涵蓋任何惡魔Throwable既不是一個錯誤也不是一個例外。 – Will 2014-10-29 21:21:48

    +1

    @只有異常和錯誤擴展Throwable和Throwable不應該直接擴展。如果存在一個既不是異常也不是錯誤的Throwable,那麼有人做了他們不應該擁有的東西。 – Radiodef 2014-10-29 21:24:36

    1

    它不正是我想要的,但我想知道是否有表達的想法更自然的方式。

    語言具有獨特的東西的語法慣用結構。在Java中,第一個選項,你發現:

    boolean ok = false; 
    try { 
        doWork(); 
        ok = true; 
    } finally { 
        if (!ok) { 
         doCleanup(); 
        } 
    } 
    

    在Java中,感覺自然的(沒有雙關語意)說語言的自然語法做的慣用方式。

    您正在尋找一種自然的僅錯誤機制,而Java沒有。您正在嘗試創建一個清理機制,而不涉及檢查的throwables上的編譯器檢查。人們會想到使用泛型,但泛型有限制(即,不能參數化可拋出的子集)。

    但是,IIRC有一些方法可以通過使用Class參數化封裝方法來規避編譯器檢查,然後製造通過反射實例並投擲它。但是,在一般情況下,現在我們正在進入毛茸茸的境界,因爲沒有明顯的和有用的理由。

    我會堅持你展示的例子。它很清楚它乾乾淨淨,沒有任何異常和意想不到的問題。

    .ps。爲了上帝的愛,我希望你不要使用C++的catch-all方法(至少不要在前面加上一組特定類型的catch塊,包括std :: exception)。

    沒有什麼比處理達到這樣一個catch-all塊的代碼更糟糕了。沒有任何驚人的信息,幾乎不可能追蹤扔掉它的東西。

    在那裏,並不是爲了生活。惡夢的東西。