Java 常用類解析:java異常機制,異常棧,異常處理方式,異常鏈,異常丟失詳解
1、java標準異常概述
Throwable表示任何可以作為異常被拋出的類,有兩個子類Error和Exception。從這兩個類的源代碼中可以看出,這兩個類并沒有添加新的方法,Throwable提供了所以方法的實現(xiàn)。Error表示編譯時和系統(tǒng)錯誤。Exception是可以被拋出的異常類。RuntimeException繼承自Exception(如NullPointerException),表示運行時異常,JVM會自動拋出.
2、自定義異常類
自定義異常類方法: 通過繼承Throwable或Exception。異常類的所有實現(xiàn)都是基類Throwable實現(xiàn)的,所以構(gòu)造自定義異常類完全可以參考Exception和Error類。我們只要添加上自定義異常類的構(gòu)造方法就可以了
<span style="font-size:16px;">package demo.others; /** * 自定義異常類方法 * 1、通過繼承Throwable * 2、通過繼承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、異常棧及異常處理方式
可以通過try、catch來捕獲異常。捕獲到的異常。下面的示例演示了幾種常用異常處理方式
<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、通過獲取棧軌跡中的元素數(shù)組來顯示異常拋出的軌跡 for (StackTraceElement ste : e.getStackTrace()) System.out.println(ste.getMethodName()); //2、直接將異常棧信息輸出至標準錯誤流或標準輸出流 e.printStackTrace();//輸出到標準錯誤流 e.printStackTrace(System.err); e.printStackTrace(System.out); //3、將異常信息輸出到文件中 //e.printStackTrace(new PrintStream("file/exception.txt")); //4、重新拋出異常,如果直接拋出那么棧路徑是完整的,如果用fillInStackTrace() //那么將會從這個方法(當前是h()方法)作為異常發(fā)生的原點。 //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>
運行結(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ù)綏5纵敵霎惓B窂健?br />
4、異常鏈
有時候我們會捕獲一個異常后在拋出另一個異常,如下代碼所示:
<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>
運行結(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é)果中我們可以看出,異常棧變小了。也就是說丟失了最原始的異常信息。怎樣保存最原始的異常信息呢?Throwable類中有個Throwable cause屬性,表示原始異常。通過接收cause參數(shù)的構(gòu)造器可以把原始異常傳遞給新異常,或者通過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é)果中看出當獲取到“重新拋出異常2的時候,同時可以輸出原始異?!爸匦聮伋龅漠惓?“和原始異?!弊远x異常,這就是異常鏈。
5、finally的使用
finally子句總是執(zhí)行的,通常用來做一些清理工作,如關(guān)閉文件,關(guān)閉連接等
下面舉幾個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));時發(fā)生異常,這時是一個文件路徑不存在的異常,也就是說并沒有打開文件,這時將會直接跳到catch塊,而不會執(zhí)行try...finally塊(并不是finally子句)里面的語句in.close();此時不需要關(guān)閉文件。
再看一個例子,會導致異常的丟失
<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();//此時捕獲g方法拋出的異常,f方法拋出的異常丟失了 } } catch (MyException e) { System.out.println(e); } } } </span>
結(jié)果:mine.util.exception.MyException: 異常2
此時異常1就丟失了
或者這樣寫:
<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會丟失所以拋出的異常 return; } } } </span>
6、異常的限制
(1)當覆蓋方法時,只能拋出在基類方法的異常說明里列出的那些異常,有些基類的方法聲明拋出異常其實并沒有拋出異常,這是因為可能在其子類的覆蓋方法中會拋出異常
(2)構(gòu)造器可以拋出任何異常而不必理會基類構(gòu)造器所拋出的異常,派生類構(gòu)造器異常說明必須包含基類構(gòu)造器異常說明,因為構(gòu)造派生類對象時會調(diào)用基類構(gòu)造器。此外,派生類構(gòu)造器不能捕獲基類構(gòu)造器拋出的異常。
感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!
相關(guān)文章
springsecurity記住我登錄時訪問無權(quán)限接口跳轉(zhuǎn)登錄界面的處理方案
這篇文章主要介紹了springsecurity記住我登錄時訪問無權(quán)限接口跳轉(zhuǎn)登錄界面的處理方案,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友參考下吧2024-02-02Spring-boot原理及spring-boot-starter實例和代碼
spring-boot的starter是一個通過maven完成自包含并通過annotation配置使得可被spring上下文發(fā)現(xiàn)并實例化的一個可插拔的組件或服務。這篇文章主要介紹了Spring-boot原理及spring-boot-starter實例和代碼 ,需要的朋友可以參考下2019-06-06java中BeanUtils.copyProperties的用法(超詳細)
本文介紹了BeanUtils.copyProperties()方法的使用,包括其功能、用法、注意事項和示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2023-08-08基于SpringBoot加載Mybatis的TypeAlias問題
這篇文章主要介紹了解決SpringBoot加載Mybatis的TypeAlias問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-07-07Java組件FileUpload上傳文件實現(xiàn)代碼
這篇文章主要為大家詳細介紹了Java組件FileUpload上傳文件實現(xiàn)代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-06-06