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ò)誤情況 ,對(duì)應(yīng)finally 塊中的代碼就不會(huì)執(zhí)行了。
⑤、面對(duì)必須要關(guān)閉的資源,我們總是應(yīng)該優(yōu)先使用 try-with-resources 而不是try-finally
try-with-resources 適用的資源包括 任何實(shí)現(xiàn)了 java.lang.AutoCloseable或者 java.io.Closeable 的對(duì)象
比如: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è)地方,以便對(duì)所有控制器進(jìn)行統(tǒng)一的異常處理、數(shù)據(jù)綁定等操作。
@RestControllerAdvice:
@RestControllerAdvice 是 @ControllerAdvice 的一個(gè)變種,用于對(duì)以 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ù)兩種方法效率對(duì)比
這篇文章主要介紹了詳解mybatis 批量更新數(shù)據(jù)兩種方法效率對(duì)比,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-02-02SpringBoot不讀取bootstrap.yml/properties文件問題
這篇文章主要介紹了SpringBoot不讀取bootstrap.yml/properties文件問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12Android Studio更改項(xiàng)目使用的JDK(詳細(xì)步驟)
本文介紹了如何在Android Studio中修改Gradle和JDK的配置步驟,包括打開設(shè)置、進(jìn)入Gradle設(shè)置、修改JDK路徑、保存并生效等,感興趣的朋友跟隨小編一起看看吧2024-11-1129個(gè)要點(diǎn)幫你完成java代碼優(yōu)化
本文給大家分享的是個(gè)人總結(jié)的29個(gè)java優(yōu)化需要注意的地方,非常的全面細(xì)致,推薦給大家,有需要的小伙伴可以參考下2015-03-03java集合之CopyOnWriteArrayList源碼解析
這篇文章主要介紹了java集合之CopyOnWriteArrayList源碼解析,容器array是volatile修飾的,即set和get方法都是線程安全的,整個(gè)添加過程上了鎖,所以整體是通過volatile和lock來保證的線程安全,需要的朋友可以參考下2023-12-12