任何一種程序設計語言設計的程序在運行時都有可能出現錯誤,例如除數爲0,數組下標越界,要讀寫的文件不存在等等。
捕獲錯誤最理想的是在編譯期間,但有的錯誤只有在運行時纔會發生。
對於這些錯誤,通常有兩種解決方法:
遇到錯誤就終止程序的運行。
由程序員在編寫程序時,就考慮到錯誤的檢測、錯誤消息的提示,以及錯誤的處理。java
異常:在Java語言中,將程序執行中發生的不正常狀況稱爲「異常」。
Java中的異經常使用於處理非預期的狀況,如文件沒找到,網絡錯誤,非法的參數程序員
Java程序運行過程當中所發生的異常事件可分爲兩類:
Error: JVM系統內部錯誤、資源耗盡等嚴重狀況
Exception: 其它因編程錯誤或偶然的外在因素致使的通常性問題,例如:
空指針訪問
試圖讀取不存在的文件
網絡鏈接中斷sql
RuntimeException
錯誤的類型轉換
數組下標越界
空指針訪問
IOExeption
從一個不存在的文件中讀取數據
越過文件結尾繼續讀取
鏈接一個不存在的URL編程
在編寫程序時,常常要在可能出現錯誤的地方加上檢測的代碼,如進行x/y運算時,要檢測分母爲0,數據爲空,輸入的不是數據而是字符等。過多的分支會致使程序的代碼加長,可讀性差。所以採用異常機制。數組
Java異常處理:Java採用異常處理機制,將異常處理的程序代碼集中在一塊兒,與正常的程序代碼分開,使得程序簡潔,並易於維護。 網絡
Java提供的是異常處理的抓拋模型。
Java程序的執行過程當中如出現異常,會自動生成一個異常類對象,該異常對象將被提交給Java運行時系統,這個過程稱爲拋出(throw)異常。
若是一個方法內拋出異常,該異常會被拋到調用方法中。若是異常沒有在調用方法中處理,它繼續被拋給這個調用方法的調用者。這個過程將一直繼續下去,直到異常被處理。這一過程稱爲捕獲(catch)異常。
若是一個異常回到main()方法,而且main()也不處理,則程序運行終止。
程序員一般只能處理Exception,而對Error無能爲力。ide
異常處理是經過try-catch-finally語句實現的。spa
try { ...... //可能產生異常的代碼 } catch( ExceptionName1 e ) { ...... //當產生ExceptionName1型異常時的處置措施 } catch( ExceptionName2 e ) { ...... //當產生ExceptionName2型異常時的處置措施 } [ finally{ ...... //無條件執行的語句 } ]
捕獲異常命令行
捕獲異常的第一步是用try{…}語句塊選定捕獲異常的範圍,將可能出現異常的代碼放在try語句塊中。設計
在catch語句塊中是對異常對象進行處理的代碼。每一個try語句塊能夠伴隨一個或多個catch語句,用於處理可能產生的不一樣類型的異常對象。
若是明確知道產生的是何種異常,能夠用該異常類做爲catch的參數;也能夠用其父類做爲catch的參數。
能夠用ArithmeticException類做爲參數,也能夠用RuntimeException類做爲參數,或者用全部異常的父類Exception類做爲參數。但不能是與ArithmeticException類無關的異常,如NullPointerException,那麼,catch中的語句將不會執行。捕獲異常的有關信息:
與其它對象同樣,能夠訪問一個異常對象的成員變量或調用它的方法。
getMessage( ) 方法,用來獲得有關異常事件的信息
printStackTrace( )用來跟蹤異常事件發生時執行堆棧的內容。
捕獲異常的最後一步是經過finally語句爲異常處理提供一個統一的出口,使得在控制流轉到程序的其它部分之前,可以對程序的狀態做統一的管理。不論在try、catch代碼塊中是否發生了異常事件,finally塊中的語句都會被執行。finally語句是可選的
package com.uncleyong; public class TestTryCatchFinally { public static void main(String[] args) { try{ int i = 10; int j = i / 0; } // catch (NullPointerException e){ // System.out.println(e.getMessage()); // } catch (ClassCastException e){ // System.out.println(e.getMessage()); // } catch (ArithmeticException e){ // java.lang.ArithmeticException;能夠寫爲Exception e,Exception是全部異常類的父類,能抓因此子類對象,因此,必須放在最後一個catch中,即父的異常類要放後面(由於它能抓全部,後面放子類的catch沒意義) // System.out.println(e.getMessage()); // return; // finally塊中的語句依舊會被執行 // } finally{ System.out.println("finally..."); } //不論在try、catch代碼塊中是否發生了異常事件,finally塊中的語句都會被執行,哪怕在抓住異常的catch代碼塊中加入return。 System.out.println("end..."); } }
前面但使用的異常都是RuntimeException類或是它的子類,這些類的異常的特色是:即便沒有使用try和catch捕獲,Java本身也能捕獲,而且編譯經過 ( 但運行時會發生異常使得程序運行終止 )。
若是拋出的異常是IOException類的異常,則必須捕獲,不然編譯錯誤。
編譯時異常示例
package com.uncleyong; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.InputStream; public class CompileException { public static void main(String[] args) { // 示例編譯時異常, IO 異常屬於編譯時異常. try { InputStream is = new FileInputStream("abc.txt"); } catch (FileNotFoundException e) { e.printStackTrace(); // System.out.println(e.getMessage()); } } }
聲明拋出異常是Java中處理異常的第二種方式
若是一個方法(中的語句執行時)可能生成某種異常,可是並不能肯定如何處理這種異常,則此方法應顯式地聲明拋出異常,代表該方法將不對這些異常進行處理,而由該方法的調用者負責處理。
在方法聲明中用 throws 子句能夠聲明拋出異常的列表,throws後面的異常類型能夠是方法中產生的異常類型,也能夠是它的父類。
聲明拋出異常舉例:
public void readFile(String file) throws FileNotFoundException { …… // 讀文件的操做可能產生FileNotFoundException類型的異常 FileInputStream fis = new FileInputStream(file); ..…… }
注意:重寫方法不能拋出比被重寫方法範圍更大的異常類型
示例
package com.uncleyong; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; public class TestThrows { public static void main(String[] args) { try { test(); } catch (Exception e) { e.printStackTrace(); } test2(); } // 編譯時時異常 // IOException異常包含FileNotFoundException異常,下面三種寫法均可以,哪怕存在父子關係,也沒有前後的順序,即FileNotFoundException不是必須在IOException前面: // FileNotFoundException, SQLException, IOException // SQLException, IOException, FileNotFoundException // SQLException, IOException public static void test() throws FileNotFoundException, SQLException, IOException { InputStream fs = new FileInputStream("abc.txt"); // FileNotFoundException Connection connection = null; String sql = null; PreparedStatement ps = connection.prepareStatement(sql); // SQLException byte [] buffer = new byte[fs.available()]; // IOException,IOException異常包含FileNotFoundException異常 // fs.read(buffer); } // 運行時異常 // 在運行的時候發生,編譯時不須要去處理,也能夠顯示拋出,系統會自動的在運行時拋出,因此運行時異常不須要使用 throws 關鍵字進行顯式的拋出 public static void test2(){ int i = 10/0; System.out.println(i); A a = new B(); // 用多態建立對象a try { a.method(); } catch (FileNotFoundException e) { e.printStackTrace(); } } } class A{ void method () throws FileNotFoundException{ } } class B extends A{ // @Override // void method(){} // 也能夠不拋異常 // @Override // void method() throws IOException { // IOException的異常範圍比FileNotFoundException大 // // } }
Java異常類對象除在程序執行過程當中出現異常時由系統自動生成並拋出,也可根據須要人工建立並拋出
首先要生成異常類對象,而後經過throw語句實現拋出操做(提交給Java運行環境)。
IOException e =new IOException(); throw e;
能夠拋出的異常必須是Throwable或其子類的實例。下面的語句在編譯時將會產生語法錯誤:
throw new String("want to throw");
用戶自定義異常類MyException,用於描述數據取值範圍錯誤信息。用戶本身的異常類必須繼承現有的異常類。
示例
編寫應用程序EcmDef.java,接收命令行的兩個參數,要求不能輸入負數,計算兩數相除。
對缺乏命令行參數(ArrayIndexOutOfBoundsException)、
除0(ArithmeticException)及輸入負數(EcDef 自定義的異常)進行異常處理。
提示:
(1)在主類(EcmDef)中定義異常方法(ecm)完成兩數相除功能。
(2)在main()方法中使用異常處理語句進行異常處理。
(3)在程序中,自定義對應輸入負數的異常類(EcDef)。
(4)運行時接受參數 java EcmDef 20 10
//args[0]=「20」 args[1]=「10」
(5)Interger類的static方法parseInt(String s)將s轉換成對應的int值。如int a=Interger.parseInt(「314」); //a=314;
package com.uncleyong; public class EcDef extends RuntimeException{ public EcDef() { } public EcDef(String msg) { super(msg); } }
package com.uncleyong; public class EcmDef { public static void main(String[] args) { try { int i = Integer.parseInt(args[0]); int j = Integer.parseInt(args[1]); System.out.println(ecm(i, j)); // 調用方法 } catch (ArrayIndexOutOfBoundsException e) { System.out.println("輸入的參數個數不足."); // 下標越界 } catch (ArithmeticException e) { System.out.println("除數不能爲 0"); } catch (EcDef e) { System.out.println(e.getMessage()); // 自定義的異常 } catch (NumberFormatException e) { System.out.println("輸入的參數不能轉爲整型."); // 輸入的"a" } } public static int ecm(int i, int j){ if(i < 0 || j < 0){ throw new EcDef("不能處理負數. "); } int result = i / j; return result; } }