[英]java: standard method of wrapping checked exceptions
我有一個相當詳細的問題,關於包裝已檢查異常的正確方法,以及Guava的方式。 (道歉,但我想讓我的思考過程失敗)
標准的Runnable接口如下所示:
public interface Runnable
{
public void run();
}
其中run()
不能拋出已檢查的異常。
因此,如果我想要一個Runnable
用於包裝拋出已檢查異常的任務,並且我打算讓調用Runnable.run()
的東西處理這些異常,而不是在Runnable.run()
本身,我必須在未經檢查的異常中包裝異常。
所以有一段時間我用的是:
Runnable r = new Runnable {
@Override public void run()
{
try {
doNastyStuff();
}
catch (NastyException e)
{
throw new RuntimeException(e);
}
}
};
然后我可以在上層處理RuntimeException。 除了我想,我真正想要的是分別處理一個包裝的異常,因為我知道它的語義是包裝一個已檢查的異常,所以我寫了這個幫助類:
/**
* Wrapped exception: the purpose of this is just to wrap another exception,
* and indicate that it is a wrapped exception
*/
public class WrappedException extends RuntimeException
{
/**
* @param t any throwable
*/
public WrappedException(Throwable t)
{
super(t);
}
}
然后我可以這樣做:
/* place that produces the exception */
...
catch (NastyException e)
{
throw new WrappedException(e);
}
...
/* upper level code that calls Runnable.run() */
try
{
...
SomeOtherNastyCode();
r.run();
...
}
catch (SomeOtherNastyException e)
{
logError(e);
}
catch (WrappedException e)
{
logError(e.getCause());
}
它看起來很棒。
但是現在我想,如果我想在庫中使用它以及使用該庫的應用程序,現在它們都依賴於WrappedException,所以它應該真正存在於我可以包含在任何地方的基礎庫中。
這讓我想到,也許Guava在某處有一個標准的WrappedException類,因為我現在默認將Guava包含為依賴。 所以我可以做到
throw new WrappedException(e);
要么
throw Exceptions.wrap(e);
要么
Exceptions.rethrow(e);
我只是在Guava中環顧四周,發現Throwables的 Throwables.propagate()
看起來很相似,但它只是在RuntimeException
包含已檢查的異常,而不是RuntimeException
的特殊子類。
哪種方法更好? 與RuntimeException相比,我不應該使用特殊的WrappedException嗎? 我的頂級代碼想知道添加信息值的最重要的異常。
如果我有一個包裝NastyException的RuntimeException包裝NullPointerException,包裝RuntimeException不會添加信息值,我不關心它,所以我記錄的錯誤將是NastyException。
如果我有一個包含NastyException的IllegalArgumentException,則IllegalArgumentException通常會添加信息值。
所以在我執行錯誤記錄的頂級代碼中,我必須執行以下操作:
catch (RuntimeException re)
{
logError(getTheOutermostUsefulException(re));
}
/**
* heuristics to tease out whether an exception
* is wrapped just for the heck of it, or whether
* it has informational value
*/
Throwable getTheOutermostUsefulException(RuntimeException re)
{
// subclasses of RuntimeException should be used as is
if (re.getClass() != RuntimeException)
return re;
// if a runtime exception has a message, it's probably useful
else if (re.getMessage() != null)
return re;
// if a runtime exception has no cause, it's certainly
// going to be more useful than null
else if (re.getCause() == null)
return re;
else
return re.getCause();
}
這種理念適合我,但實施感覺很糟糕。 有沒有更好的方法來處理包裝異常?
相關問題:
Spring是我所知道的唯一一個相對類似的庫。 它們具有嵌套異常: NestedRuntimeException和NestedCheckedException 。 這些異常具有有用的方法,例如getMostSpecificCause()
或contains(Class exType)
。 他們的getMessage()
方法返回cause的消息(如果包裝異常已經有消息,則會附加它)。
它用在Spring的數據訪問異常層次結構中。 這個想法是每個數據庫供應商在其JDBC驅動程序中公開不同的異常。 Spring捕獲它們並將它們轉換為更通用的DataAccessExceptions 。 這樣做的另一個好處是,已檢查的異常會自動轉換為運行時異常。
話雖如此,代碼並不是很復雜,我相信你可以在你的代碼庫中做類似的事情。 不需要為此添加Spring依賴項。
如果我是你,我不會試圖過早地“解開”異常,除非你真的可以在那時和那里處理它們。 我會讓它們冒泡(包裝或不包裝),使用全局ExceptionHandler查看其因果鏈,找到第一個“有意義”的異常,並提取智能錯誤消息。 如果無法這樣做,我只會打印“技術錯誤”並在錯誤消息的詳細信息或某種日志中添加整個堆棧跟蹤,以便進行錯誤報告。 然后,您將修復錯誤和/或拋出更有意義的異常。
Guava的Throwables.getCausalChain()也可能有助於簡化異常處理:
Iterables.filter(Throwables.getCausalChain(e), IOException.class));
編輯:
我更多地考慮了你的問題,我認為你不應該真的擔心用特定的“WrapperException”類型包裝你的異常。 您應該使用最有意義的東西來包裝它們:要么是簡單的RuntimeException
(Guava的Throwables.propagate()
可能在那里有用),帶有附加錯誤消息的RuntimeException
,或者適當時更有意義的異常類型。
Java的因果鏈機制無論如何都會讓你找到根本原因。 您不必擔心代碼中的異常包裝。 編寫一個全局異常處理程序來管理它,並在其他地方使用標准異常冒泡。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.