Java 常用類(lèi)解析:java異常機(jī)制,異常棧,異常處理方式,異常鏈,異常丟失詳解
1、java標(biāo)準(zhǔn)異常概述
Throwable表示任何可以作為異常被拋出的類(lèi),有兩個(gè)子類(lèi)Error和Exception。從這兩個(gè)類(lèi)的源代碼中可以看出,這兩個(gè)類(lèi)并沒(méi)有添加新的方法,Throwable提供了所以方法的實(shí)現(xiàn)。Error表示編譯時(shí)和系統(tǒng)錯(cuò)誤。Exception是可以被拋出的異常類(lèi)。RuntimeException繼承自Exception(如NullPointerException),表示運(yùn)行時(shí)異常,JVM會(huì)自動(dòng)拋出.
2、自定義異常類(lèi)
自定義異常類(lèi)方法: 通過(guò)繼承Throwable或Exception。異常類(lèi)的所有實(shí)現(xiàn)都是基類(lèi)Throwable實(shí)現(xiàn)的,所以構(gòu)造自定義異常類(lèi)完全可以參考Exception和Error類(lèi)。我們只要添加上自定義異常類(lèi)的構(gòu)造方法就可以了
<span style="font-size:16px;">package demo.others;
/**
* 自定義異常類(lèi)方法
* 1、通過(guò)繼承Throwable
* 2、通過(guò)繼承Exception
*
* @author Touch
*/
public class MyExceptionDemo extends Exception {
private static final long serialVersionUID = 1L;
public MyExceptionDemo() {
super();
}
public MyExceptionDemo(String message) {
super(message);
}
public MyExceptionDemo(String message, Throwable cause) {
super(message, cause);
}
public MyExceptionDemo(Throwable cause) {
super(cause);
}
}
</span>
3、異常棧及異常處理方式
可以通過(guò)try、catch來(lái)捕獲異常。捕獲到的異常。下面的示例演示了幾種常用異常處理方式
<span style="font-size:16px;">package demo.others;
import mine.util.exception.MyException;
public class ExceptionDemo1 {
public void f() throws MyException {
throw new MyException("自定義異常");
}
public void g() throws MyException {
f();
}
public void h() throws MyException {
try {
g();
} catch (MyException e) {
//1、通過(guò)獲取棧軌跡中的元素?cái)?shù)組來(lái)顯示異常拋出的軌跡
for (StackTraceElement ste : e.getStackTrace())
System.out.println(ste.getMethodName());
//2、直接將異常棧信息輸出至標(biāo)準(zhǔn)錯(cuò)誤流或標(biāo)準(zhǔn)輸出流
e.printStackTrace();//輸出到標(biāo)準(zhǔn)錯(cuò)誤流
e.printStackTrace(System.err);
e.printStackTrace(System.out);
//3、將異常信息輸出到文件中
//e.printStackTrace(new PrintStream("file/exception.txt"));
//4、重新拋出異常,如果直接拋出那么棧路徑是完整的,如果用fillInStackTrace()
//那么將會(huì)從這個(gè)方法(當(dāng)前是h()方法)作為異常發(fā)生的原點(diǎn)。
//throw e;
throw (MyException)e.fillInStackTrace();
}
}
public static void main(String[] args) {
try {
new ExceptionDemo1().h();
} catch (MyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
</span>
運(yùn)行結(jié)果:
f g h main mine.util.exception.MyException: 自定義異常 at demo.others.ExceptionDemo1.f(ExceptionDemo1.Java:7) at demo.others.ExceptionDemo1.g(ExceptionDemo1.Java:11) at demo.others.ExceptionDemo1.h(ExceptionDemo1.java:16) at demo.others.ExceptionDemo1.main(ExceptionDemo1.java:35) mine.util.exception.MyException: 自定義異常 at demo.others.ExceptionDemo1.f(ExceptionDemo1.java:7) at demo.others.ExceptionDemo1.g(ExceptionDemo1.java:11) at demo.others.ExceptionDemo1.h(ExceptionDemo1.java:16) at demo.others.ExceptionDemo1.main(ExceptionDemo1.java:35) mine.util.exception.MyException: 自定義異常 at demo.others.ExceptionDemo1.f(ExceptionDemo1.java:7) at demo.others.ExceptionDemo1.g(ExceptionDemo1.java:11) at demo.others.ExceptionDemo1.h(ExceptionDemo1.java:16) at demo.others.ExceptionDemo1.main(ExceptionDemo1.java:35) mine.util.exception.MyException: 自定義異常 at demo.others.ExceptionDemo1.h(ExceptionDemo1.java:30) at demo.others.ExceptionDemo1.main(ExceptionDemo1.java:35)
分析上面的程序,首先main函數(shù)被調(diào)用,然后是調(diào)用h函數(shù),再g函數(shù)、f函數(shù),f函數(shù)拋出異常,并在h函數(shù)捕獲,這時(shí)將依次從棧頂?shù)綏5纵敵霎惓B窂健?br />
4、異常鏈
有時(shí)候我們會(huì)捕獲一個(gè)異常后在拋出另一個(gè)異常,如下代碼所示:
<span style="font-size:16px;">package demo.others;
import java.io.IOException;
import mine.util.exception.MyException;
public class ExceptionDemo2 {
public void f() throws MyException {
throw new MyException("自定義異常");
}
public void g() throws Exception {
try {
f();
} catch (MyException e) {
e.printStackTrace();
throw new Exception("重新拋出的異常1");
}
}
public void h() throws IOException {
try {
g();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
throw new IOException("重新拋出異常2");
}
}
public static void main(String[] args) {
try {
new ExceptionDemo2().h();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
</span>
運(yùn)行結(jié)果:
mine.util.exception.MyException: 自定義異常 at demo.others.ExceptionDemo2.f(ExceptionDemo2.java:9) at demo.others.ExceptionDemo2.g(ExceptionDemo2.java:14) at demo.others.ExceptionDemo2.h(ExceptionDemo2.java:23) at demo.others.ExceptionDemo2.main(ExceptionDemo2.java:32) java.lang.Exception: 重新拋出的異常1 at demo.others.ExceptionDemo2.g(ExceptionDemo2.java:17) at demo.others.ExceptionDemo2.h(ExceptionDemo2.java:23) at demo.others.ExceptionDemo2.main(ExceptionDemo2.java:32) java.io.IOException: 重新拋出異常2 at demo.others.ExceptionDemo2.h(ExceptionDemo2.java:27) at demo.others.ExceptionDemo2.main(ExceptionDemo2.java:32)
從結(jié)果中我們可以看出,異常棧變小了。也就是說(shuō)丟失了最原始的異常信息。怎樣保存最原始的異常信息呢?Throwable類(lèi)中有個(gè)Throwable cause屬性,表示原始異常。通過(guò)接收cause參數(shù)的構(gòu)造器可以把原始異常傳遞給新異常,或者通過(guò)initCause()方法。如下示例:
<span style="font-size:16px;">package demo.others;
import java.io.IOException;
import mine.util.exception.MyException;
public class ExceptionDemo2 {
public void f() throws MyException {
throw new MyException("自定義異常");
}
public void g() throws Exception {
try {
f();
} catch (MyException e) {
e.printStackTrace();
throw new Exception("重新拋出的異常1",e);
}
}
public void h() throws IOException {
try {
g();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
IOException io=new IOException("重新拋出異常2");
io.initCause(e);
throw io;
}
}
public static void main(String[] args) {
try {
new ExceptionDemo2().h();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
</span>
結(jié)果:
mine.util.exception.MyException: 自定義異常 at demo.others.ExceptionDemo2.f(ExceptionDemo2.java:9) at demo.others.ExceptionDemo2.g(ExceptionDemo2.java:14) at demo.others.ExceptionDemo2.h(ExceptionDemo2.java:23) at demo.others.ExceptionDemo2.main(ExceptionDemo2.java:34) java.lang.Exception: 重新拋出的異常1 at demo.others.ExceptionDemo2.g(ExceptionDemo2.java:17) at demo.others.ExceptionDemo2.h(ExceptionDemo2.java:23) at demo.others.ExceptionDemo2.main(ExceptionDemo2.java:34) Caused by: mine.util.exception.MyException: 自定義異常 at demo.others.ExceptionDemo2.f(ExceptionDemo2.java:9) at demo.others.ExceptionDemo2.g(ExceptionDemo2.java:14) ... 2 more java.io.IOException: 重新拋出異常2 at demo.others.ExceptionDemo2.h(ExceptionDemo2.java:27) at demo.others.ExceptionDemo2.main(ExceptionDemo2.java:34) Caused by: java.lang.Exception: 重新拋出的異常1 at demo.others.ExceptionDemo2.g(ExceptionDemo2.java:17) at demo.others.ExceptionDemo2.h(ExceptionDemo2.java:23) ... 1 more Caused by: mine.util.exception.MyException: 自定義異常 at demo.others.ExceptionDemo2.f(ExceptionDemo2.java:9) at demo.others.ExceptionDemo2.g(ExceptionDemo2.java:14) ... 2 more
從結(jié)果中看出當(dāng)獲取到“重新拋出異常2的時(shí)候,同時(shí)可以輸出原始異常“重新拋出的異常1“和原始異?!弊远x異常,這就是異常鏈。
5、finally的使用
finally子句總是執(zhí)行的,通常用來(lái)做一些清理工作,如關(guān)閉文件,關(guān)閉連接等
下面舉幾個(gè)finally的例子:
<span style="font-size:16px;">// 讀取指定路徑文本文件
public static String read(String filePath) {
StringBuilder str = new StringBuilder();
BufferedReader in = null;
try {
in = new BufferedReader(new FileReader(filePath));
String s;
try {
while ((s = in.readLine()) != null)
str.append(s + '\n');
} finally {
in.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return str.toString();
}</span>
分析:如果調(diào)用in = new BufferedReader(new FileReader(filePath));時(shí)發(fā)生異常,這時(shí)是一個(gè)文件路徑不存在的異常,也就是說(shuō)并沒(méi)有打開(kāi)文件,這時(shí)將會(huì)直接跳到catch塊,而不會(huì)執(zhí)行try...finally塊(并不是finally子句)里面的語(yǔ)句in.close();此時(shí)不需要關(guān)閉文件。
再看一個(gè)例子,會(huì)導(dǎo)致異常的丟失
<span style="font-size:16px;">package demo.others;
import mine.util.exception.MyException;
public class ExceptionDemo3 {
public void f() throws MyException {
throw new MyException("異常1");
}
public void g() throws MyException {
throw new MyException("異常2");
}
public static void main(String[] args) {
try {
ExceptionDemo3 ex = new ExceptionDemo3();
try {
ex.f();
} finally {
ex.g();//此時(shí)捕獲g方法拋出的異常,f方法拋出的異常丟失了
}
} catch (MyException e) {
System.out.println(e);
}
}
}
</span>
結(jié)果:mine.util.exception.MyException: 異常2
此時(shí)異常1就丟失了
或者這樣寫(xiě):
<span style="font-size:16px;">package demo.others;
import mine.util.exception.MyException;
public class ExceptionDemo3 {
public void g() throws MyException {
throw new MyException("異常2");
}
public static void main(String[] args) {
ExceptionDemo3 ex = new ExceptionDemo3();
try {
ex.g();
} finally {
//直接return會(huì)丟失所以拋出的異常
return;
}
}
}
</span>
6、異常的限制
(1)當(dāng)覆蓋方法時(shí),只能拋出在基類(lèi)方法的異常說(shuō)明里列出的那些異常,有些基類(lèi)的方法聲明拋出異常其實(shí)并沒(méi)有拋出異常,這是因?yàn)榭赡茉谄渥宇?lèi)的覆蓋方法中會(huì)拋出異常
(2)構(gòu)造器可以拋出任何異常而不必理會(huì)基類(lèi)構(gòu)造器所拋出的異常,派生類(lèi)構(gòu)造器異常說(shuō)明必須包含基類(lèi)構(gòu)造器異常說(shuō)明,因?yàn)闃?gòu)造派生類(lèi)對(duì)象時(shí)會(huì)調(diào)用基類(lèi)構(gòu)造器。此外,派生類(lèi)構(gòu)造器不能捕獲基類(lèi)構(gòu)造器拋出的異常。
感謝閱讀,希望能幫助到大家,謝謝大家對(duì)本站的支持!
相關(guān)文章
JDBC中PreparedStatement詳解以及應(yīng)用場(chǎng)景實(shí)例介紹
PreparedStatement對(duì)象代表的是一個(gè)預(yù)編譯的SQL語(yǔ)句,用它提供的setter方法可以傳入查詢(xún)的變量,這篇文章主要給大家介紹了關(guān)于JDBC中PreparedStatement詳解以及應(yīng)用場(chǎng)景實(shí)例介紹的相關(guān)資料,需要的朋友可以參考下2024-02-02
servlet之ServletContext簡(jiǎn)介_(kāi)動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要介紹了servlet之ServletContext簡(jiǎn)介,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-07-07
FastJson踩坑:@JsonField在反序列化時(shí)失效的解決
這篇文章主要介紹了FastJson踩坑:@JsonField在反序列化時(shí)失效的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06
Spring?Boot?JWT登錄授權(quán)使用(無(wú)感刷新)
JWT作為一種輕量級(jí)的身份認(rèn)證與授權(quán)方案,憑借其無(wú)狀態(tài)、可跨域、易于擴(kuò)展的特性,成為?Spring?Boot?項(xiàng)目中實(shí)現(xiàn)認(rèn)證授權(quán)的主流選擇,本文詳解Spring?Boot整合?JWT?實(shí)現(xiàn)登錄認(rèn)證與授權(quán)的全流程,助力開(kāi)發(fā)者快速搭建安全可靠的認(rèn)證授權(quán)體系,感興趣的可以了解一下2026-04-04
Mybatis利用分頁(yè)插件PageHelper快速實(shí)現(xiàn)分頁(yè)查詢(xún)
如果你也在用MyBatis,建議嘗試該分頁(yè)插件,這一定是最方便使用的分頁(yè)插件,這篇文章主要給大家介紹了關(guān)于Mybatis利用分頁(yè)插件PageHelper快速實(shí)現(xiàn)分頁(yè)查詢(xún)的相關(guān)資料,PageHelper是一個(gè)Mybatis的分頁(yè)插件,負(fù)責(zé)將已經(jīng)寫(xiě)好的sql語(yǔ)句,進(jìn)行分頁(yè)加工,需要的朋友可以參考下2021-08-08
Java中Object.equals和String.equals的區(qū)別詳解
這篇文章主要給大家介紹了Java中Object.equals和String.equals的區(qū)別,文中通過(guò)一個(gè)小示例讓大家輕松的明白這兩者的區(qū)別,對(duì)大家具有一定的參考價(jià)值,需要的朋友們下面來(lái)一起看看吧。2017-04-04
Mybatis如何動(dòng)態(tài)創(chuàng)建表
這篇文章主要介紹了Mybatis如何動(dòng)態(tài)創(chuàng)建表問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-04-04

