Java的異常處理體系詳解
異常處理
1、Java的異常類層次結(jié)構(gòu)

其中Error表示程序運(yùn)行錯誤
常見的錯誤類型有:
- OutOfMemoryError (內(nèi)存溢出錯誤)
- StackOverFlowError (棧內(nèi)存溢出錯誤)
- IOError (IO錯誤)
- 等
Exception表示程序本身可以處理的異常
其中Exception又分為
①、CheckedException (檢查異常 必須在代碼中顯式處理 使用try catch捕獲 或者 在方法上使用 throws 拋出 除了RuntimeException及其子類以外,其他的Exception類及其子類都屬于受檢查異常 )
常見的包括:
- IO Exception
- SQL Exception
- FileNotFoundException
- ClassNotFoundException
- 等
②、UncheckedException(非檢查異常 不用顯式捕獲 或者 throws拋出 )
常見的包括:
- NullPointerException(空指針異常)
- ClassCastException (類型轉(zhuǎn)換錯誤)
- IndexOutOfBoundsException (數(shù)組下標(biāo)越界)
- ConcurrentModificationException(并發(fā)修改異常)
- NumberFormatException(數(shù)字轉(zhuǎn)換異常)
- ArithmeticException(算數(shù)異常)
- IllegalArgumentException(參數(shù)錯誤)
- UnsupportedOperationException(不支持的操作 比如使用Arrays.asList生成的集合 無法使用增刪改操作)
- 等
2、try-catch-finally 使用注意事項
①、try塊:用于捕獲異常。其后可接零個或多個 catch 塊,如果沒有 catch 塊,則必須跟一個 finally 塊。
②、當(dāng)在try 塊 或 catch塊遇到 return語句時 finally 塊會在 方法返回之前執(zhí)行
③、不要在 finally 塊中使用 return 語句 ,當(dāng) try 語句和 finally 語句中都有 return 語句時,try 語句塊中的 return 語句會被忽略。這是因為 try 語句中的 return 返回值會先被暫存在一個本地變量中,當(dāng)執(zhí)行到 finally 語句中的 return 之后,這個本地變量的值就變?yōu)榱?finally 語句中的 return 返回值。
示例:
public int foo() {
try {
// some code that may throw an exception
return 1;
} catch (Exception e) {
// handle exception
return 2;
} finally {
return 3;
}
}
在這個例子中,無論 try 塊中的代碼是否拋出異常,finally 塊中的 return 3; 語句都會執(zhí)行,而且會覆蓋 try 塊和 catch 塊中的 return 語句,導(dǎo)致 foo() 方法始終返回3;
④、finally 塊中的代碼不一定會被執(zhí)行 ,如果在try 或者 catch塊中 出現(xiàn)了內(nèi)存溢出或者jvm退出( System.exit(1);)等錯誤情況 ,對應(yīng)finally 塊中的代碼就不會執(zhí)行了。
⑤、面對必須要關(guān)閉的資源,我們總是應(yīng)該優(yōu)先使用 try-with-resources 而不是try-finally
try-with-resources 適用的資源包括 任何實現(xiàn)了 java.lang.AutoCloseable或者 java.io.Closeable 的對象
比如:Java 中類似于InputStream、OutputStream這類IO資源 需要我們使用完畢后手動關(guān)閉資源的
//讀取文本文件的內(nèi)容 BufferedReader 需要在使用完畢后手動釋放資源
public static void main(String[] args) {
String fileName = "C:\\Users\\Administrator\\Desktop\\數(shù)據(jù)分片.txt";
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(fileName))
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line); // 處理每一行的內(nèi)容
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//讀取文本文件的內(nèi)容 BufferedReader 在使用完畢后自動釋放資源 (Java 7 之后支持try-with-resources )
public static void main(String[] args) {
String fileName = "C:\\Users\\Administrator\\Desktop\\數(shù)據(jù)分片.txt";
try (BufferedReader reader = new BufferedReader(new FileReader(fileName))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line); // 處理每一行的內(nèi)容
}
} catch (IOException e) {
e.printStackTrace();
}
}
//讀取文本文件的內(nèi)容 如果有多個資源同時聲明 可以使用分號分隔即可
public static void main(String[] args) {
String fileName = "C:\\Users\\Administrator\\Desktop\\數(shù)據(jù)分片.txt";
try (BufferedReader reader = new BufferedReader(new FileReader(fileName)); Scanner scanner = new Scanner(new File(fileName));) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line); // 處理每一行的內(nèi)容
}
System.out.println("=====>>>>>>>>>>>>>>>>>>>>>>>>");
while (scanner.hasNext()) {
System.out.println(scanner.nextLine()); // 處理每一行的內(nèi)容
}
} catch (IOException e) {
e.printStackTrace();
}
}
⑥、不要省略異常信息的記錄 在catch塊中 使用日志記錄關(guān)鍵異常信息
記錄信息時盡量只寫一個log.error或者log.info語句 , 因為在多線程環(huán)境下 兩個相鄰的日志語句不一定打印在相鄰的位置
public void aa() {
try {
int a = 1/0;
} catch (Exception e) {
// 這里一定要記錄完整的異常信息
log.error("哦,錯誤竟然發(fā)生了: {}" , e);
}
}
3、在Web應(yīng)用中如何實現(xiàn)全局異常處理機(jī)制
主要利用 @ControllerAdvice或者@RestControllerAdvice注解
@ControllerAdvice:
@ControllerAdvice 注解用于定義全局控制器建議,在 Spring MVC 中,控制器建議由控制器中的 @ExceptionHandler 方法、@InitBinder 方法和 @ModelAttribute 方法組成。通過 @ControllerAdvice 注解的類,可以將這些方法集中到一個地方,以便對所有控制器進(jìn)行統(tǒng)一的異常處理、數(shù)據(jù)綁定等操作。
@RestControllerAdvice:
@RestControllerAdvice 是 @ControllerAdvice 的一個變種,用于對以 REST 風(fēng)格提供 API 服務(wù)的控制器進(jìn)行全局建議定義。與 @ControllerAdvice 類似,@RestControllerAdvice 注解的類可以包含全局異常處理、全局?jǐn)?shù)據(jù)綁定等方法,但它專門用于 RESTful 服務(wù),可以將異常信息轉(zhuǎn)化為 JSON 格式返回給客戶端。
總的來說,@ControllerAdvice 用于傳統(tǒng)的基于視圖的控制器,而 @RestControllerAdvice 用于 RESTful 服務(wù)的控制器
一般情況下 建議在Web應(yīng)用中捕獲自定義異常 在自定義異常中拋出自定義錯誤代碼 并且返回給前端 方便快速排查問題 或者提示用戶相關(guān)業(yè)務(wù)的錯誤信息
①、利用枚舉類型 自定義錯誤代碼
/**
* 自定義錯誤類型
* */
public enum MyErrorCode {
EMPTY_PARAM_ERROR("EMPTY_PARAM_ERROR", "遠(yuǎn)程調(diào)用錯誤"),
REMOTE_ERROR("REMOTE_ERROR", "遠(yuǎn)程調(diào)用錯誤"),
;
private final String code;
private final String text;
MyErrorCode(String code, String text) {
this.code = code;
this.text = text;
}
public String getText() {
return text;
}
public String getCode() {
return code;
}
}
②、自定義異常 繼承自RuntimeException
/**
* 自定義異常
* */
public class MyException extends RuntimeException {
/**
* 錯誤代碼
*/
private String errorCode;
/**
* 格式化異常參數(shù)
*/
private List<String> paramList;
/**
* 最常用的方法
* @param MyErrorCode 自定義錯誤代碼
*/
public MyException(MyErrorCode MyErrorCode) {
this(MyErrorCode.getCode(), MyErrorCode.getText(), null);
}
public MyException(String errorCode, String message) {
this(errorCode, message, null);
}
private MyException(String errorCode, String message, Throwable cause) {
super(message, cause);
this.errorCode = errorCode;
}
public MyException(MyErrorCode MyErrorCode, Throwable cause) {
this(MyErrorCode.getCode(), MyErrorCode.getText(), cause);
}
public MyException(MyErrorCode MyErrorCode, List<String> params) {
this(MyErrorCode.getCode(), MyErrorCode.getText(), null);
this.paramList = params;
}
public List<String> getParamList() {
return paramList;
}
public void setParamList(List<String> paramList) {
this.paramList = paramList;
}
public String getErrorCode() {
return this.errorCode;
}
}
③、異常處理類
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.util.List;
@Slf4j
@RestControllerAdvice
public class MyExceptionHandle {
@ExceptionHandler(MyException.class)
public JsonResult<?> handleMyException(MyException e) {
String message = e.getMessage();
log.error("current web request error:" + message, e);
JsonResult<Object> jsonResult = new JsonResult<>(false, message);
String errorCode = e.getErrorCode();
jsonResult.setErrCode(errorCode);
List<String> paramList = e.getParamList();
jsonResult.setData(paramList);
return jsonResult;
}
/**
* 處理未知異常
*
* @return JsonResult
*/
@ExceptionHandler(Exception.class)
private JsonResult<?> handleUnKnownException(Exception e) {
if (null == e || StringUtils.isBlank(e.getMessage())) {
log.error("current web request error:", e);
return new JsonResult<Object>(false, "500", "unknownException", e);
}
String message = e.getMessage();
log.error("current web request error:" + message, e);
e.printStackTrace();
JsonResult<Object> jsonResult = new JsonResult<>(false, "500", message, e);
jsonResult.setMsg("unknownException");
return jsonResult;
}
}
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
以Json形式的數(shù)據(jù)格式實現(xiàn)JMeter參數(shù)化
本文以小項目學(xué)院管理系統(tǒng)為例,給大家分享以Json形式的數(shù)據(jù)格式實現(xiàn)JMeter參數(shù)化的相關(guān)知識,包括添加元件操作步驟及使用用戶參數(shù)組件實現(xiàn)參數(shù)化的方法,感興趣的朋友跟隨小編一起看看吧2021-05-05
使用@Autowired注解警告Field injection is not recommended的解決
這篇文章主要介紹了使用@Autowired注解警告Field injection is not recommended的解決,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-04-04
springboot jpa分庫分表項目實現(xiàn)過程詳解
這篇文章主要介紹了springboot jpa分庫分表項目實現(xiàn)過程詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-01-01

