分享一個(gè)你不知道的Java異常實(shí)現(xiàn)的缺陷
前言
Java中一個(gè)大家熟知的知識(shí)點(diǎn)就是異常捕獲,try...catch...finally組合,但是很多人不知道這里面有一個(gè)關(guān)于Java的缺陷,或者說是異常實(shí)現(xiàn)的一點(diǎn)不足之處。
我這邊就通過一個(gè)很簡單的實(shí)驗(yàn)給大家演示下效果玩玩兒,希望大家能覺得有趣。
模擬
1、自定義異常
這里,我們首先寫一個(gè)自定義業(yè)務(wù)異常,專門用來拋出。
/**
* <p>
* 自定義業(yè)務(wù)異常
* </p>
*
* @author 程序員濟(jì)癲,公眾號(hào):【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、模擬異常
然后,我們寫個(gè)測試方法來捕獲并拋出空指針異常。
/**
* <p>
* 測試異常缺陷
* </p>
*
* @author 程序員濟(jì)癲,公眾號(hào):【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 程序員濟(jì)癲,公眾號(hào):【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中拋出一個(gè)異常。
/**
* <p>
* 測試異常缺陷
* </p>
*
* @author 程序員濟(jì)癲,公眾號(hào):【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的異常竟然被覆蓋了。

雖然這種場景很特殊,但這其實(shí)就是Java在異常實(shí)現(xiàn)上美中不足的地方,因?yàn)楫惓J亲鳛槌绦虺鲥e(cuò)的標(biāo)志絕對不應(yīng)忽略,可是這種場景下異常的的確確丟失了。
接下來,我們再測試一種情況,在finally中使用return,看看會(huì)發(fā)生什么。
/**
* <p>
* 測試異常缺陷
* </p>
*
* @author 程序員濟(jì)癲,公眾號(hào):【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中捕獲的異常干脆直接沒了,仿佛從沒來過。

最后,我們再演示一種你可能工作中干過或者見過的莫名其妙的事情。
我們修改一下這個(gè)測試方法,看代碼。
/**
* <p>
* 測試異常缺陷
* </p>
*
* @author 程序員濟(jì)癲,公眾號(hào):【Java分享客?!?
* @since 2022/12/6 19:22
*/
@Slf4j
public class ExceptionTest {
public static void main(String[] args) {
try {
// 調(diào)用其他類的查詢方法
queryData();
} catch (Exception ex) {
// 捕獲這個(gè)查詢方法拋出的異常
throw new BusinessException(ex.getMessage());
}
}
private static void queryData() {
try {
// 這個(gè)方法剛好你也try..catch了,并且在finally中做了一些末尾必須執(zhí)行的業(yè)務(wù)邏輯處理。
UserInfo userInfo = null;
System.err.println(userInfo.getName());
} finally {
doSomething();
}
}
private static void doSomething() {
// 業(yè)務(wù)處理過程中你同樣習(xí)慣性地拋出了某個(gè)業(yè)務(wù)異常
System.err.println("--------處理末尾業(yè)務(wù)--------");
throw new BusinessException("處理末尾業(yè)務(wù)拋出邏輯異常");
}
}
簡單描述一下,你調(diào)用其他類的一個(gè)查詢方法,那個(gè)方法可能習(xí)慣性的try..catch..finally了,而finally中還做了一些末尾必須要執(zhí)行的操作,這個(gè)業(yè)務(wù)邏輯處理可能有幾十行,你很可能又習(xí)慣性的做了一些判斷以及異常的拋出。
別不相信,當(dāng)一個(gè)項(xiàng)目進(jìn)入中期甚至趕進(jìn)度的時(shí)候,方法套方法,不少人已經(jīng)在機(jī)械的茫然的寫代碼,也可能是在別人的基礎(chǔ)上改代碼,你很可能不會(huì)太仔細(xì)地一行一行去看那些代碼里究竟有什么,恰巧測試的時(shí)候也沒出什么大問題。
那么結(jié)果可能就是下面這樣,你會(huì)發(fā)現(xiàn)自己一開始特意拋出的那個(gè)捕獲該查詢方法異常的玩意兒沒一點(diǎn)效果,也不知道去哪兒了,怎么找也找不到,不知從哪兒冒出來下面這個(gè)莫名其妙的異常,后來想不到也就算了。

原因
這其實(shí)就是Java異常實(shí)現(xiàn)的一個(gè)不足,異常是程序出錯(cuò)的標(biāo)志,怎么都不應(yīng)該被忽略掉,更不用說是finally這種常用的行為,直接或間接地造成了異常的丟失。
《Thinking In Java》的作者有明確指出這個(gè)異常,認(rèn)為這是相當(dāng)嚴(yán)重的缺陷,是一個(gè)可能造成異常完全丟失的缺陷,而且是以一種更微妙、更難以察覺的方式在進(jìn)行。
而C++就處理的很好,會(huì)將這種在第一個(gè)異常被處理之前拋出第二個(gè)異常的情況視為嚴(yán)重的編程錯(cuò)誤。
總結(jié)
知道了這個(gè)缺陷后,其實(shí)就很好避免了。
1、避免在finally中拋出異常;
2、避免在finally中使用return;
3、catch中一定要養(yǎng)成log.error記錄異常日志的好習(xí)慣,因?yàn)閘og是一定會(huì)記錄下來的,至少不會(huì)讓你毫無線索。
結(jié)尾再演示下加了日志的效果,只要是catch我都加上日志,那么一定不會(huì)錯(cuò)過。

到此這篇關(guān)于分享一個(gè)你不知道的Java異常實(shí)現(xiàn)的缺陷的文章就介紹到這了,更多相關(guān)Java異常實(shí)現(xiàn)缺陷內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java實(shí)現(xiàn)鎖定某個(gè)變量的幾種方式示例詳解
這篇文章主要為大家介紹了Java實(shí)現(xiàn)鎖某個(gè)變量的幾種方式示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-09-09
在Java開發(fā)中無法繞開的SpringBoot框架詳解
SpringBoot是一個(gè)基于Spring框架的快速開發(fā)框架,它的出現(xiàn)極大地簡化了Spring應(yīng)用的開發(fā)流程,SpringBoot是一個(gè)快速開發(fā)的框架,它提供了一種快速構(gòu)建應(yīng)用程序的方式,本文給大家介紹在Java開發(fā)中無法繞開的框架:SpringBoot,感興趣的朋友一起看看吧2023-09-09
eclipse+maven+spring mvc項(xiàng)目基本搭建過程
這篇文章主要介紹了eclipse+maven+spring mvc項(xiàng)目基本搭建過程,本文圖文并茂給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-09-09

