1. 拋出異常
- 通過throw new
ThrowableClass文法可以拋出一個異常,其中ThrowableClass是一個從Throwable繼承的類,或者是Throwable類本身,先看下面的
public void proc(){<br /> // Exception是Throwable的繼承類,代表最基本的異常<br /> throw new Exception("hello");<br />}<br />
- 上面的代碼會導致編譯錯誤,對於有拋出異常的方法,編譯器強制要求:要麼在方法上聲明要拋出的異常(稱為異常說明),要麼在方法中用try塊捕獲這個異常。
// 用異常說明,說明該方法要拋出的異常<br />public void proc() throws Exception{<br /> throw new Exception("hello");<br />}</p><p>// 用try塊捕獲該異常<br />public void proc(){<br /> try {<br /> throw new Exception("hello");<br /> } catch (Exception e) {<br /> e.printStackTrace();<br /> }<br />}
異常說明可以是方法拋出的異常類本身,也可以是異常類的基類,比如throws後面可以是throwable。
- 上面說到對於有拋出異常的方法,必須帶有方法聲明,這並不準確,當拋出的異常類是RuntimeException或其繼承類時,不需要異常說明:
// RuntimeException或其繼承類不需要異常聲明<br />public void proc(){<br /> throw new RuntimeException("hello");<br />}
- 一個方法即使內部沒有拋出異常,也仍然可以帶有異常說明:
public void proc2() throws NullPointerException, FileNotFoundException {<br />}
- 一個方法若帶有異常說明,則調用它的其他方法也要帶有異常說明,或者要捕獲可能拋出的異常:
class A {<br /> public void proc() throws Exception {<br /> throw new Exception("hello");<br /> }<br /> // 異常聲明<br /> public void proc1() throws Exception {<br /> proc();<br /> }<br /> // 異常聲明,聲明中的類可以是基類<br /> public void proc2() throws Throwable {<br /> proc();<br /> }<br /> // 直接捕獲異常<br /> public void proc3() {<br /> try {<br /> proc();<br /> } catch (Exception e) {<br /> e.printStackTrace();<br /> }<br /> }<br />}
class MyException1 extends Exception {<br />}<br />class MyException2 extends Exception {<br />}<br />class A {<br /> public void proc() throws MyException1, MyException2{<br /> }<br />}<br />
2. 捕獲異常和結束清理
- 用try{}塊包圍住可能引發異常的代碼,後面緊跟著異常處理器(即catch(...){}塊);catch塊可以有多個,()中聲明要捕獲的異常類。當try塊拋出一個異常時,執行代碼將跳到catch塊去,並從第一個catch塊開始匹配,直到找到符合的catch塊。請看下面的代碼說明:
class MyException1 extends Exception {<br />}<br />class MyException2 extends Exception {<br />}<br />class MyException3 extends Exception {<br />}<br />class A {<br /> public void proc() throws Exception{<br /> try{<br /> // 僅僅為了示範用<br /> Random random = new Random();<br /> int i = random.nextInt(3);<br /> if (i == 0)<br /> throw new MyException1();<br /> else if (i == 1)<br /> throw new MyException2();<br /> else if (i == 2)<br /> throw new MyException3();<br /> }<br /> catch(MyException1 e){<br /> // 當拋出MyException1時會跳到這裡來。<br /> e.printStackTrace();<br /> }<br /> catch(MyException2 e){<br /> // 當拋出MyException2時會跳到這裡來。<br /> e.printStackTrace();<br /> }<br /> catch (Exception e) {<br /> // 當拋出MyException3時,由於上面沒有匹配的處理器,<br /> // 並且Exception是MyException3的基類,所以會跳到這裡來。<br /> e.printStackTrace();<br /> // 可以重新拋出異常,系統將尋找更外層的異常處理器<br /> throw e;<br /> }<br /> }<br />}</p><p>public class Main {<br /> public static void main(String[] args) {<br /> A a = new A();<br /> try {<br /> a.proc();<br /> } catch (Exception e) {<br /> e.printStackTrace();<br /> }<br /> }<br />}
- 在異常處理器後面加上finally子句,無論異常是否發生,finally子句一定會被調用到,finally子句常被用於清理記憶體回收之外的資源,比如開啟的檔案,網路連結等:
class MyException1 extends Exception {<br />}</p><p>class A {<br /> public void proc(){<br /> try{<br /> throw new MyException1();<br /> }<br /> catch(MyException1 e){<br /> e.printStackTrace();<br /> }<br /> finally {<br /> System.out.println("Hello");<br /> }<br /> }<br />}</p><p>public class Main {<br /> public static void main(String[] args) {<br /> A a = new A();<br /> a.proc();<br /> }<br />}<br />最後的輸出是:<br />MyException1<br /> at A.proc(Main.java:12)<br /> at Main.main(Main.java:27)<br />Hello<br />
3. 異常的限制:對於繼承類,它如果所覆蓋的方法有異常說明,則所列出的異常類,必須是基類該方法所列出的異常類的子集,先看一個例子:
class MyException1 extends Exception {<br />}<br />class A {<br /> public void proc(){<br /> }<br />}<br />class B extends A {<br /> // 編譯錯誤:因為A.proc沒有異常說明,所以子類也不能有異常說明<br /> // 解決的方法是為A.proc加上異常說明:throws MyException1<br /> // 或者在throw new MyException1();加上try塊並去掉異常說明<br /> public void proc() throws MyException1 {<br /> throw new MyException1();<br /> }<br />}<br />
再看一下例子:
class MyException1 extends Exception {<br />}<br />class MyException2 extends Exception {<br />}<br />class A {<br /> public void proc() throws MyException1 {<br /> }<br />}<br />class B extends A {<br /> // 錯誤:因為A.proc只聲明了MyException1異常<br /> public void proc() throws MyException2 {<br /> }<br />}
構造器是一個例外,繼承類可以聲明更多的異常類,但必須加上基類所聲明的異常類:
class MyException1 extends Exception {<br />}<br />class MyException2 extends Exception {<br />}<br />class A {<br /> A() throws MyException1 {</p><p> }<br /> public void proc() throws MyException1 {<br /> }<br />}<br />class B extends A {<br /> B() throws MyException1, MyException2 {<br /> }<br />}<br />