想象一些代碼:
public void doSomething(Object object){
try {
if (object == null)
throw new BusinessException("Object was null");
try {
// do logic actions
} catch (Exception e) {
throw new BusinessException("Something went wrong doing logic", e)
}
try {
// do some IO actions
} catch (Exception e) {
throw new BusinessException("Something went wrong doing IO.", e)
}
} catch(Exception e){
throw new BusinessException("Something went wrong in doSomething.", e)
}
}
該BusinessException是的擴展RuntimeException。我的經理和另一位高級工程師告訴我,這BusinessException是唯一應該拋出的例外,并且每個方法都應該像上述方法一樣設計以確保這一點。任何時候出現問題,他們都希望BusinessException拋出同樣的問題。
他們的想法是他們想從用戶那里“抽象”掉邏輯例外,只向用戶提供“業務例外”。我的經理不希望我們只捕獲特定的例外,例如,IOException他們希望始終catch(Exception)確保沒有遺漏任何內容。
我不明白他們談論的這種“抽象”。我很確定沒有任何東西被“抽象”掉,一個例外只是被封裝(或屏蔽)在一個新的例外中。
拋開語意不談,我覺得這真的很奇怪,我正在努力理解他們認為這種冗長的例外處理提供的價值。我不難想象這會使除錯變得更加困難。如果拋出任何業務例外,它會立即被另一個 catch 塊捕獲并重新包裝到一個新的例外中,從而使堆疊跟蹤和潛在的除錯作業復雜化。
有這么多例外實體化似乎也是一個性能問題。
此外,這是一個 spring boot 應用程式,我們已經有了一個 ResponseEntityExceptionHandler
@ControllerAdvice
public class MyAppResponseEntityExceptionHandler extends ResponseEntityExceptionHandler{
@ExceptionHandler(value = { IllegalArgumentException.class })
protected ResponseEntity<Object> handleConflict(IllegalArgumentException ex, WebRequest request) {
String bodyOfResponse = "Check the arguments";
return handleExceptionInternal(ex, bodyOfResponse, new HttpHeaders(), HttpStatus.CONFLICT, request);
}
// Several more for different exception types...
}
這只是“各自為政”的情況還是客觀上存在問題?
uj5u.com熱心網友回復:
首先,從不建議使用通用catch塊來捕獲Throwableor 的實體Exception,除非它存在于一個 catch 塊鏈中,例如:
public void doSomething() {
try {
// do some database stuff
} catch (SQLException e) {
throw new BusinessException("something went wrong with database", e);
}
try {
// do some IO stuff
} catch (IOException e) {
throw new BusinessException("something went wrong with IO");
}
}
現在除了這兩個例外之外的任何東西都不應該被捕獲,因為這不是這個特定函式的責任,函式應該只抱怨與其所做的相關的錯誤。
作為來電者,我可能會做這樣的事情:
SomethingDoer s = new SomethingDoer();
s.doSomething();
現在,如果我擔心例外可能會意外拋出,作為呼叫者,我有責任處理它,因此 API 委托呼叫者處理未捕獲的例外,如下所示:
SomethingDoer s = new SomethingDoer();
try {
s.doSomething();
} catch ( BusinessException e) {
LOGGER.error(e.message) // prod logging
LOGGER.debug(e) // debug logging with stacktrace
// hypothetical error listener
errorListener.onError(e);
//handle or log, but not rethrow.
} catch (Exception e) { // cringe..
LOGGER.error("something went wrong, unexpectedly"); // prod logs
LOGGER.debug("something went wrong, unexpectedly", e); // debug logs with stacktrace
/* logged AND rethrown since up till this point all expected
exceptions should be wrapped and rethrown or logged,
so if we get here its a fatal error, and you need to interrupt the application*/
throw e;
后者 - 畏縮外觀 -
catch( Exception e)塊也不推薦,例外應該沿堆疊向上傳播到主執行緒,檢查例外通常以這種方式處理。
因此,特定于語言的例外 - 內部 - 應該在到達ControllerAdvice處理程式和此處理程式之前捕獲并包裝在 BusinessException 中- 因為它相對靠近應用程式的視圖層,應該只處理業務特定的例外而不是內部例外。
uj5u.com熱心網友回復:
您的經理和高級工程師可能正在考慮Effective Java。從第三版開始,第 73 條:拋出適合抽象的例外。
當一個方法拋出一個與它執行的任務沒有明顯聯系的例外時,這是令人不安的。當方法傳播由較低級別的抽象拋出的例外時,通常會發生這種情況。它不僅令人不安,而且用實作細節污染了更高層的 API。如果更高層的實作在以后的版本中發生變化,它拋出的例外也會發生變化,可能會破壞現有的客戶端程式。
為了避免這個問題,高層應該捕獲低層例外,并在它們的位置拋出可以用高層抽象來解釋的例外。這個習語被稱為例外翻譯。
也許你的經理對這些建議過于熱心了。有效的 Java 繼續謹慎,
雖然例外翻譯優于從低層無意識地傳播例外,但不應過度使用它。
你可能有理由向你的經理指出這種過度使用,但我懷疑說服會很困難。您可以在條款 72:支持使用標準例外中獲得一些安慰。我個人更喜歡這個建議,并且傾向于避免創建自定義例外,但當然其他開發人員會有不同的感受。
uj5u.com熱心網友回復:
就像,最終用戶不知道如何處理例外,所以通用例外會更好。
您可以為 diff 型別的操作撰寫 diff 自定義例外,例如資料庫呼叫、api 呼叫,并且只向呼叫者回傳一種型別的例外。
即您可以像這樣定義自定義例外。
public class BusinessException extends RuntimeException {
private final ErrorCodes errorCode;
private final Object body;
public BusinessException(String message, ErrorCodes errorCode) {
super(message);
this.errorCode = errorCode;
this.body = null;
}
public BusinessException(String message, ErrorCodes errorCode, Object body) {
super(message);
this.errorCode = errorCode;
this.body = body;
}
}
其中 ErrorCodes 是將包含諸如 InternalError、EntityNotFound、Unauthorised 之類的 ErrorCode 的列舉。
現在您可以使用此自定義例外,您將捕獲應用程式中的任何例外并拋出此例外并帶有正確的錯誤訊息和錯誤代碼。
像這樣的東西。
throw new BusinessException("Error while fetching some api data.", INTERNAL_SERVER_ERROR);
或者
throw new ServiceException("User is not authorised to perform operation.", UNAUTHORIZED);
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/324119.html
