簡體   English   中英

Java:如何在插入異常時傳播“方法退出”?

[英]Java: How to propagate a "method exit" when tucking-in exceptions?

  • 通過“方法退出”-我的意思是方法中的操作,例如returnthrow new...編譯器認為方法結束-如果您能告訴我“方法退出”的可接受詞,我將進行編輯問題

我的問題如下:

  • 我做了很多throw new RuntimeException(...

  • 所以,我決定把它“ public static void quickRaise (String msg) { throw new RuntimeException(msg); }去”: public static void quickRaise (String msg) { throw new RuntimeException(msg); } public static void quickRaise (String msg) { throw new RuntimeException(msg); }

    然后我可以重復使用它。
    (這將幫助我在未來增強有關引發運行時異常的過程,甚至切換到自定義 Exception 類,而無需在代碼中尋找異常拋出)

  • 但是,在我可以寫之前的地方:

     public MyType doSomething() { try { //... return new MyType (parameter); } catch (Exception e) { throw new RuntimeException("msg") } }

    並且編譯器會正確理解“此方法要么通過返回退出要么通過拋出退出”,因此沒有邏輯上的“死胡同”

當我將throw new RuntimeException("msg")更改為quickRaise("msg") ,編譯器不再認為我的方法“完成”。 它抱怨缺少 return 語句,即使quickRaise在語義上等同於throw (或者至少這是我想要做的!)

讓我嘗試通過一個重現的例子來重申這個問題(這將無法編譯,這就是問題所在):

public static void main(String[] args) {
    System.out.println(doSomething());
}
public static String doSomething () {
    try {
        //... Some fun stuff going on here
        return "Something";
    } catch (Exception e) {
        quickRaise("Could not find handshakes");
        //throw new RuntimeException("If you uncomment this line, it will compile!");
    }
}
public static void quickRaise (String msg) {
    throw new RuntimeException(msg);
}

你的想法是非常不可取的。

例如,這只是糟糕的代碼風格:

try {
   someIO();
} catch (IOException e) {
   throw new RuntimeException("Problem with IO");
}

糟糕的原因是您現在已經抹去了有關問題的實際信息。 該信息被鎖定在您剛剛捕獲的異常的 5 個獨立部分中:它的類型(例如FileNotFoundException 、它的消息(例如“目錄 /foo/bar 不存在”)、它的堆棧跟蹤、它的因果鏈和作為 throwables是對象,該特定類型異常的任何特定額外細節(例如某些 SQLException 的特定於 DB 引擎的錯誤編碼)。

扔掉這些信息是愚蠢的。

要解決此問題,您只需添加原因:

} catch (IOException e) {
    throw new RuntimeException("IO problem", e);
}

現在 IOException 被標記為您拋出的異常的原因,這意味着在錯誤日志中您將看到它 + 消息 + 它的堆棧跟蹤 + 任何原因的堆棧跟蹤。

要讓編譯器意識到該方法到此結束,您需要做的就是拋出它:

public static RuntimeException quickRaise(String msg) {
    throw new RuntimeException(msg);
    return null; // doesn't matter, we never get here
}

// to use:

throw quickRaise(msg);

但是,正如我之前所解釋的,這是一個非常糟糕的主意。

其次,“我只是想拋出一個異常,也許以后我想替換我拋出的那種異常”的想法也沒有真正解決:你需要為這種情況選擇一個合適的異常,因此你不能首先編寫一個通用的 throw 方法。

好的,那我該怎么辦?

首先,學會接受throws子句。 如果您的方法從根本上執行 I/O(例如,它的 javadoc 和/或名稱使其顯而易見,例如saveGame(Path p)scanUserHome ),則應聲明它throws IOException

如果您的方法是一個入口點(例如,它是您自己的代碼開始運行的第一個點),那么您的方法應該聲明為throws Exception 例如,您的public static void main()方法應該throws Exception 有時入口點不是主要的而是其他東西(例如 webhandler 路由鈎子),有時向后愚蠢的 franeworks 阻止你這樣做,但往往有一個包裝功能(例如} catch (Exception e) { throw new ServletException(e); } )。

對於既 [A] 基本上不是方法目的的一部分,而是實現細節的更多部分的異常,[B] 不太可能出錯,除了硬崩潰之外,你無能為力,然后,是的,重新包裝為 RuntimeException。 對於所有此類異常,在“全局”更改此值並沒有多大意義。 充其量你遲到地意識到失敗的可能性比你最初想象的要大一點,要么為其創建一個適當的例外並記錄這種行為。 但這又是基於每個方法,而不是您可以以一攬子方式應用的東西。

您的方法從根本上與編譯器需要查看流程在 throw 語句處終止的需求不一致。

我建議使用一個只構造一個異常的實用方法,然后您從原始點拋出該異常。

在每次調用 quickRaise() 之后,它不是或放置虛擬返回。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM