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

其中Error表示程序運(yùn)行錯(cuò)誤
常見的錯(cuò)誤類型有:
- OutOfMemoryError (內(nèi)存溢出錯(cuò)誤)
- StackOverFlowError (棧內(nèi)存溢出錯(cuò)誤)
- IOError (IO錯(cuò)誤)
- 等
Exception表示程序本身可以處理的異常
其中Exception又分為
①、CheckedException (檢查異常 必須在代碼中顯式處理 使用try catch捕獲 或者 在方法上使用 throws 拋出 除了RuntimeException及其子類以外,其他的Exception類及其子類都屬于受檢查異常 )
常見的包括:
- IO Exception
- SQL Exception
- FileNotFoundException
- ClassNotFoundException
- 等
②、UncheckedException(非檢查異常 不用顯式捕獲 或者 throws拋出 )
常見的包括:
- NullPointerException(空指針異常)
- ClassCastException (類型轉(zhuǎn)換錯(cuò)誤)
- IndexOutOfBoundsException (數(shù)組下標(biāo)越界)
- ConcurrentModificationException(并發(fā)修改異常)
- NumberFormatException(數(shù)字轉(zhuǎn)換異常)
- ArithmeticException(算數(shù)異常)
- IllegalArgumentException(參數(shù)錯(cuò)誤)
- UnsupportedOperationException(不支持的操作 比如使用Arrays.asList生成的集合 無法使用增刪改操作)
- 等
2、try-catch-finally 使用注意事項(xiàng)
①、try塊:用于捕獲異常。其后可接零個(gè)或多個(gè) catch 塊,如果沒有 catch 塊,則必須跟一個(gè) finally 塊。
②、當(dāng)在try 塊 或 catch塊遇到 return語句時(shí) finally 塊會(huì)在 方法返回之前執(zhí)行
③、不要在 finally 塊中使用 return 語句 ,當(dāng) try 語句和 finally 語句中都有 return 語句時(shí),try 語句塊中的 return 語句會(huì)被忽略。這是因?yàn)?try 語句中的 return 返回值會(huì)先被暫存在一個(gè)本地變量中,當(dāng)執(zhí)行到 finally 語句中的 return 之后,這個(gè)本地變量的值就變?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;
}
}
在這個(gè)例子中,無論 try 塊中的代碼是否拋出異常,finally 塊中的 return 3; 語句都會(huì)執(zhí)行,而且會(huì)覆蓋 try 塊和 catch 塊中的 return 語句,導(dǎo)致 foo() 方法始終返回3;
④、finally 塊中的代碼不一定會(huì)被執(zhí)行 ,如果在try 或者 catch塊中 出現(xiàn)了內(nèi)存溢出或者jvm退出( System.exit(1);)等錯(cuò)誤情況 ,對應(yīng)finally 塊中的代碼就不會(huì)執(zhí)行了。
⑤、面對必須要關(guān)閉的資源,我們總是應(yīng)該優(yōu)先使用 try-with-resources 而不是try-finally
try-with-resources 適用的資源包括 任何實(shí)現(xiàn)了 java.lang.AutoCloseable或者 java.io.Closeable 的對象
比如:Java 中類似于InputStream、OutputStream這類IO資源 需要我們使用完畢后手動(dòng)關(guān)閉資源的
//讀取文本文件的內(nèi)容 BufferedReader 需要在使用完畢后手動(dòng)釋放資源
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 在使用完畢后自動(dòng)釋放資源 (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)容 如果有多個(gè)資源同時(shí)聲明 可以使用分號(hào)分隔即可
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)鍵異常信息
記錄信息時(shí)盡量只寫一個(gè)log.error或者log.info語句 , 因?yàn)樵诙嗑€程環(huán)境下 兩個(gè)相鄰的日志語句不一定打印在相鄰的位置
public void aa() {
try {
int a = 1/0;
} catch (Exception e) {
// 這里一定要記錄完整的異常信息
log.error("哦,錯(cuò)誤竟然發(fā)生了: {}" , e);
}
}
3、在Web應(yīng)用中如何實(shí)現(xiàn)全局異常處理機(jī)制
主要利用 @ControllerAdvice或者@RestControllerAdvice注解
@ControllerAdvice:
@ControllerAdvice 注解用于定義全局控制器建議,在 Spring MVC 中,控制器建議由控制器中的 @ExceptionHandler 方法、@InitBinder 方法和 @ModelAttribute 方法組成。通過 @ControllerAdvice 注解的類,可以將這些方法集中到一個(gè)地方,以便對所有控制器進(jìn)行統(tǒng)一的異常處理、數(shù)據(jù)綁定等操作。
@RestControllerAdvice:
@RestControllerAdvice 是 @ControllerAdvice 的一個(gè)變種,用于對以 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)用中捕獲自定義異常 在自定義異常中拋出自定義錯(cuò)誤代碼 并且返回給前端 方便快速排查問題 或者提示用戶相關(guān)業(yè)務(wù)的錯(cuò)誤信息
①、利用枚舉類型 自定義錯(cuò)誤代碼
/**
* 自定義錯(cuò)誤類型
* */
public enum MyErrorCode {
EMPTY_PARAM_ERROR("EMPTY_PARAM_ERROR", "遠(yuǎn)程調(diào)用錯(cuò)誤"),
REMOTE_ERROR("REMOTE_ERROR", "遠(yuǎn)程調(diào)用錯(cuò)誤"),
;
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 {
/**
* 錯(cuò)誤代碼
*/
private String errorCode;
/**
* 格式化異常參數(shù)
*/
private List<String> paramList;
/**
* 最常用的方法
* @param MyErrorCode 自定義錯(cuò)誤代碼
*/
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é)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java中使用開源庫JSoup解析HTML文件實(shí)例
這篇文章主要介紹了Java中使用開源庫JSoup解析HTML文件實(shí)例,Jsoup是一個(gè)開源的Java庫,它可以用于處理實(shí)際應(yīng)用中的HTML,比如常見的HTML格式化就可以用它來實(shí)現(xiàn),需要的朋友可以參考下2014-09-09
詳解Java動(dòng)態(tài)代理的實(shí)現(xiàn)機(jī)制
這篇文章主要為大家詳細(xì)介紹了Java動(dòng)態(tài)代理的實(shí)現(xiàn)機(jī)制,感興趣的小伙伴們可以參考一下2016-03-03
詳解mybatis 批量更新數(shù)據(jù)兩種方法效率對比
這篇文章主要介紹了詳解mybatis 批量更新數(shù)據(jù)兩種方法效率對比,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-02-02
SpringBoot不讀取bootstrap.yml/properties文件問題
這篇文章主要介紹了SpringBoot不讀取bootstrap.yml/properties文件問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12
Android Studio更改項(xiàng)目使用的JDK(詳細(xì)步驟)
本文介紹了如何在Android Studio中修改Gradle和JDK的配置步驟,包括打開設(shè)置、進(jìn)入Gradle設(shè)置、修改JDK路徑、保存并生效等,感興趣的朋友跟隨小編一起看看吧2024-11-11
29個(gè)要點(diǎn)幫你完成java代碼優(yōu)化
本文給大家分享的是個(gè)人總結(jié)的29個(gè)java優(yōu)化需要注意的地方,非常的全面細(xì)致,推薦給大家,有需要的小伙伴可以參考下2015-03-03
java集合之CopyOnWriteArrayList源碼解析
這篇文章主要介紹了java集合之CopyOnWriteArrayList源碼解析,容器array是volatile修飾的,即set和get方法都是線程安全的,整個(gè)添加過程上了鎖,所以整體是通過volatile和lock來保證的線程安全,需要的朋友可以參考下2023-12-12

