分享一個你不知道的Java異常實現(xiàn)的缺陷
前言
Java中一個大家熟知的知識點就是異常捕獲,try...catch...finally組合,但是很多人不知道這里面有一個關(guān)于Java的缺陷,或者說是異常實現(xiàn)的一點不足之處。
我這邊就通過一個很簡單的實驗給大家演示下效果玩玩兒,希望大家能覺得有趣。
模擬
1、自定義異常
這里,我們首先寫一個自定義業(yè)務(wù)異常,專門用來拋出。
/** * <p> * 自定義業(yè)務(wù)異常 * </p> * * @author 程序員濟癲,公眾號:【Java分享客?!? * @since 2022/12/6 19:20 */ public class BusinessException extends RuntimeException { public BusinessException() { super(); } public BusinessException(String errMsg) { super(errMsg); } public BusinessException(String errMsg, Throwable throwable) { super(errMsg, throwable); } }
2、模擬異常
然后,我們寫個測試方法來捕獲并拋出空指針異常。
/** * <p> * 測試異常缺陷 * </p> * * @author 程序員濟癲,公眾號:【Java分享客?!? * @since 2022/12/6 19:22 */ @Slf4j public class ExceptionTest { public static void main(String[] args) { try { UserInfo userInfo = null; System.err.println(userInfo.getName()); } catch (Exception ex) { throw new BusinessException("捕獲try的異常: " + ex.getMessage()); } } }
看下效果,OK沒問題。
接下來,我們加上finally看看。
/** * <p> * 測試異常缺陷 * </p> * * @author 程序員濟癲,公眾號:【Java分享客?!? * @since 2022/12/6 19:22 */ @Slf4j public class ExceptionTest { public static void main(String[] args) { try { UserInfo userInfo = null; System.err.println(userInfo.getName()); } catch (Exception ex) { throw new BusinessException("捕獲try的異常: " + ex.getMessage()); } finally { System.err.println("----------finally最終執(zhí)行---------"); } } }
看下效果,OK也沒問題。
接下來我們這么做,在finally中拋出一個異常。
/** * <p> * 測試異常缺陷 * </p> * * @author 程序員濟癲,公眾號:【Java分享客?!? * @since 2022/12/6 19:22 */ @Slf4j public class ExceptionTest { public static void main(String[] args) { try { UserInfo userInfo = null; System.err.println(userInfo.getName()); } catch (Exception ex) { throw new BusinessException("捕獲try的異常: " + ex.getMessage()); } finally { System.err.println("----------finally最終執(zhí)行---------"); throw new BusinessException("覆蓋catch的異常"); } } }
看下效果,發(fā)現(xiàn)catch的異常竟然被覆蓋了。
雖然這種場景很特殊,但這其實就是Java在異常實現(xiàn)上美中不足的地方,因為異常是作為程序出錯的標志絕對不應(yīng)忽略,可是這種場景下異常的的確確丟失了。
接下來,我們再測試一種情況,在finally中使用return,看看會發(fā)生什么。
/** * <p> * 測試異常缺陷 * </p> * * @author 程序員濟癲,公眾號:【Java分享客?!? * @since 2022/12/6 19:22 */ @Slf4j public class ExceptionTest { public static void main(String[] args) { try { UserInfo userInfo = null; System.err.println(userInfo.getName()); } catch (Exception ex) { throw new BusinessException("捕獲try的異常: " + ex.getMessage()); } finally { System.err.println("----------finally最終執(zhí)行---------"); return; } } }
看看效果,發(fā)現(xiàn)catch中捕獲的異常干脆直接沒了,仿佛從沒來過。
最后,我們再演示一種你可能工作中干過或者見過的莫名其妙的事情。
我們修改一下這個測試方法,看代碼。
/** * <p> * 測試異常缺陷 * </p> * * @author 程序員濟癲,公眾號:【Java分享客?!? * @since 2022/12/6 19:22 */ @Slf4j public class ExceptionTest { public static void main(String[] args) { try { // 調(diào)用其他類的查詢方法 queryData(); } catch (Exception ex) { // 捕獲這個查詢方法拋出的異常 throw new BusinessException(ex.getMessage()); } } private static void queryData() { try { // 這個方法剛好你也try..catch了,并且在finally中做了一些末尾必須執(zhí)行的業(yè)務(wù)邏輯處理。 UserInfo userInfo = null; System.err.println(userInfo.getName()); } finally { doSomething(); } } private static void doSomething() { // 業(yè)務(wù)處理過程中你同樣習(xí)慣性地拋出了某個業(yè)務(wù)異常 System.err.println("--------處理末尾業(yè)務(wù)--------"); throw new BusinessException("處理末尾業(yè)務(wù)拋出邏輯異常"); } }
簡單描述一下,你調(diào)用其他類的一個查詢方法,那個方法可能習(xí)慣性的try..catch..finally了,而finally中還做了一些末尾必須要執(zhí)行的操作,這個業(yè)務(wù)邏輯處理可能有幾十行,你很可能又習(xí)慣性的做了一些判斷以及異常的拋出。
別不相信,當(dāng)一個項目進入中期甚至趕進度的時候,方法套方法,不少人已經(jīng)在機械的茫然的寫代碼,也可能是在別人的基礎(chǔ)上改代碼,你很可能不會太仔細地一行一行去看那些代碼里究竟有什么,恰巧測試的時候也沒出什么大問題。
那么結(jié)果可能就是下面這樣,你會發(fā)現(xiàn)自己一開始特意拋出的那個捕獲該查詢方法異常的玩意兒沒一點效果,也不知道去哪兒了,怎么找也找不到,不知從哪兒冒出來下面這個莫名其妙的異常,后來想不到也就算了。
原因
這其實就是Java異常實現(xiàn)的一個不足,異常是程序出錯的標志,怎么都不應(yīng)該被忽略掉,更不用說是finally這種常用的行為,直接或間接地造成了異常的丟失。
《Thinking In Java》的作者有明確指出這個異常,認為這是相當(dāng)嚴重的缺陷,是一個可能造成異常完全丟失的缺陷,而且是以一種更微妙、更難以察覺的方式在進行。
而C++就處理的很好,會將這種在第一個異常被處理之前拋出第二個異常的情況視為嚴重的編程錯誤。
總結(jié)
知道了這個缺陷后,其實就很好避免了。
1、避免在finally中拋出異常;
2、避免在finally中使用return;
3、catch中一定要養(yǎng)成log.error記錄異常日志的好習(xí)慣,因為log是一定會記錄下來的,至少不會讓你毫無線索。
結(jié)尾再演示下加了日志的效果,只要是catch我都加上日志,那么一定不會錯過。
到此這篇關(guān)于分享一個你不知道的Java異常實現(xiàn)的缺陷的文章就介紹到這了,更多相關(guān)Java異常實現(xiàn)缺陷內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
在Java開發(fā)中無法繞開的SpringBoot框架詳解
SpringBoot是一個基于Spring框架的快速開發(fā)框架,它的出現(xiàn)極大地簡化了Spring應(yīng)用的開發(fā)流程,SpringBoot是一個快速開發(fā)的框架,它提供了一種快速構(gòu)建應(yīng)用程序的方式,本文給大家介紹在Java開發(fā)中無法繞開的框架:SpringBoot,感興趣的朋友一起看看吧2023-09-09eclipse+maven+spring mvc項目基本搭建過程
這篇文章主要介紹了eclipse+maven+spring mvc項目基本搭建過程,本文圖文并茂給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下2019-09-09