要理解Java異常處理是如何工作的,你需要掌握以下三種類型的異常:
- 檢查性異常:
最具代表的檢查性異常是用戶錯誤或問題引起的異常,這是程序員無法預見的。例如要打開一個不存在文件時,一個異常就發生了,這些異常在編譯時不能被簡單地忽略。 - 運行時異常:
運行時異常是可能被程序員避免的異常。與檢查性異常相反,運行時異常可以在編譯時被忽略。 - 錯誤:
錯誤不是異常,而是脫離程序員控制的問題。錯誤在代碼中通常被忽略。例如,當棧溢出時,一個錯誤就發生了,它們在編譯也檢查不到的。
一.Exception 類的層次
從繼承關係可知:Throwable是異常體系的根,它繼承自Object。Throwable有兩個體系:Error和Exception,Error表示嚴重的錯誤,程序對此一般無能爲力,例如:
1.OutOfMemoryError
:內存耗盡
2.NoClassDefFoundError
:無法加載某個Class
3.StackOverflowError
:棧溢出
而Exception則是運行時的錯誤,它可以被捕獲並處理。某些異常是應用程序邏輯處理的一部分,應該捕獲並處理。例如:
1.NumberFormatException
:數值類型的格式錯誤
2.FileNotFoundException
:未找到文件
3.SocketException
:讀取網絡失敗
還有一些異常是程序邏輯編寫不對造成的,應該修復程序本身。例如:
1.NullPointerException
:對某個null的對象調用方法或字段
2.IndexOutOfBoundsException
:數組索引越界
Exception又分爲兩大類:
1.RuntimeException
以及它的子類;
2.非RuntimeException
(包括IOException
、ReflectiveOperationException
等等)
Java規定:
必須捕獲的異常,包括Exception及其子類,但不包括RuntimeException及其子類,這種類型的異常稱爲Checked Exception。
不需要捕獲的異常,包括Error及其子類,RuntimeException及其子類。
二.捕獲異常
捕獲異常使用try…catch語句,把可能發生異常的代碼放到try {…}中,然後使用catch捕獲對應的Exception及其子類
try {
Integer.valueOf("22m");
} catch (NumberFormatException e) {
e.printStackTrace();
}
在異常捕獲的同時,我們希望同時輸出異常的詳細信息,大多數情況下會選擇e.printStackTrace();
這個方法,但是他對於系統 的性能會有一定的影響,先不說開銷的問題,有些時候我們需要做一些自定義的輸出,與log系統進行結合,可是e.printStackTrace();
並沒有返回值,這就很尷尬,接下來我們自定義異常收集器
三.自定義異常收集器
3.1 定義log輸出的模板
設計的理念:
1.我們採用模板的設計模式定義接口,如果小夥伴對模板模式不了接,請看這篇文章https://blog.csdn.net/weixin_38937840/article/details/104211816
2.我們獲取堆裏的異常信息(當然獲取Throwable ,Exception也是可以),源碼在文末會提供
public abstract class LogTemplate {
/**前綴*/
protected static final String PREFIX = "Java有貨";
/**鏈接符*/
protected static final String JOINER = "-----";
/**
* <p>
* 自定義前綴輸出
* </p>
* /
protected abstract void logError(String prefix,StackTraceElement[] stackTrace);
/**
* <p>
* 默認前綴統一輸出
* </p>
*/
protected abstract void logError(StackTraceElement[] stackTrace);
// protected abstract void logError(String prefix, Exception e);
// protected abstract void logError(Exception e);
// protected abstract void logError(String prefix, Throwable e);
// protected abstract void logError(Throwable e);
protected boolean verify(String prefix){
boolean blank = StringUtils.isEmpty(prefix);
return blank;
}
/**
* 統一日誌出口
*/
public void logPrint(String prefix, StackTraceElement[] stackTrace){
boolean verify = verify(prefix);
if (verify){
logError(stackTrace);
}else {
logError(prefix,stackTrace);
}
}
3.2 實現自定義輸出
@Slf4j
public class LogError extends LogTemplate {
@Autowired(required = false)
private TaskExecutor taskExecutor;
private static final String MSG = " 錯誤詳細信息 : ";
/**
* <p>
* 錯誤日誌記錄
* </p>
*/
@Override
protected void logError(String prefix,StackTraceElement[] stackTrace) {
log(prefix ,stackTrace );
}
/**
* <p>
* 錯誤日誌記錄
* </p>
*/
@Override
protected void logError(StackTraceElement[] stackTrace) {
log(stackTrace);
}
/**
* <p>
* 錯誤日誌記錄,內部輸出
* </p>
*/
private void log(String prefix,StackTraceElement[] stackTrace){
CompletableFuture.runAsync(() -> {
for (StackTraceElement stackTraceElement : stackTrace) {
log.error(PREFIX + JOINER + prefix.trim() + JOINER + "{}",MSG+ stackTraceElement.toString());
}
},taskExecutor);
}
/**
* <p>
* 錯誤日誌記錄,內部輸出
* </p>
*/
private void log(StackTraceElement[] stackTrace){
CompletableFuture.runAsync(() -> {
for (StackTraceElement stackTraceElement : stackTrace) {
log.error(PREFIX + "{}", JOINER +MSG+ stackTraceElement);
}
},taskExecutor);
}
}
這裏使用了CompletableFuture,如果不瞭解的同學,請看下面的文章
https://blog.csdn.net/weixin_38937840/article/details/105046588
3.3 使用驗證
try {
Integer.valueOf("22m");
} catch (NumberFormatException e) {
logError.logPrint("swagger",e.getStackTrace());
}
如下圖,這時我們就可以與業務場景進行高度結合,快速定位
源碼地址:https://github.com/Dylan-haiji/javayh-platform/tree/master/javayh-starter/javayh-log-starter/src/main/java/com/javayh/log/log
本文的分享暫時就到這裏,希望對您有所幫助
關注 Java有貨領取更多資料
聯繫小編。微信:372787553,帶您進羣互相學習
左側小編微信,右側獲取免費資料
- SpringCloud 自定義封裝架構https://github.com/Dylan-haiji/javayh-platform
- Java 設計模式學習代碼 https://github.com/Dylan-haiji/design-pattern
- SpringCloud學習代碼: https://github.com/Dylan-haiji/javayh-cloud
- AlibabaCloud學習代碼:https://github.com/Dylan-haiji/javayh-cloud-nacos
- SpringBoot+Mybatis 多數據源切換:https://github.com/Dylan-haiji/javayh-boot-data-soure
- Redis、Mongo、Rabbitmq、Kafka學習代碼: https://github.com/Dylan-haiji/javayh-middleware
- SpringBoot+SpringSecurity實現自定義登錄學習代碼:https://github.com/Dylan-haiji/javayh-distribution