一篇搞定异常: Exception
文章目錄
- 1.什么是異常?
- 2.異常的分類
- 2.1 Error與Exception
- 2.2 編譯時與運行時異常(受檢異常與非受檢異常)
- 3.常見的具體異常
- 4.如何處理異常?
- 4.1 異常的處理機制
- 4.2 代碼中捕獲異常:try-catch-finally
- 4.3 方法中聲明拋出異常:throws + 異常類型
- 4.4 手動拋出異常:throw + 異常對象
- 4.5 自定義異常類
- 5.一張圖概覽關鍵字
本文已同步到: https://www.bithachi.cn/posts/23a3bd72.html
1.什么是異常?
在使用計算機語言進行項目開發的過程中,即使程序員把代碼寫得 盡善盡美,在系統的運行過程中仍然會遇到一些問題,因為很多問題不是靠代碼能夠避免的,比如:客戶輸入數據的格式,讀取文件是否存在,網絡是否始終保持通暢,,棧溢出,堆溢出等等。這些錯誤就叫做異常。
異常:在Java語言中,將程序執行中發生的不正常情況稱為“異常”。(開發過程中的語法錯誤和邏輯錯誤不是異常)
2.異常的分類
2.1 Error與Exception
Java程序在執行過程中所發生的異常事件可分為兩類:
-
Error :Java虛擬機無法解決的嚴重問題。如:JVM系統內部錯誤、資源耗盡等嚴重情況。比如:StackOverflowError、VirtualMachineError、OOM(OutOfMemoryError)、ThreadDeath。一般不編寫針對性的代碼進行處理。這些異常發生時,Java 虛擬機(JVM)一般會選擇線程終止。
public class ErrorTest {public static void main(String[] args) {//1.棧溢出:java.lang.StackOverflowError // main(args);//2.堆溢出:java.lang.OutOfMemoryError Integer[] arr = new Integer[1024*1024*1024];} } -
Exception: 因編程錯誤或偶然的外在因素導致的一般性問題,可以使用針對性的代碼進行處理。例如:
- 空指針訪問
- 試圖讀取不存在的文件
- 網絡連接中斷
- 數組角標越界
Exception能被程序本身處理,Error是無法處理
對于Error和Exception,一般有兩種 解決方法:
捕獲錯誤最理想的是在 編譯期間,但有的錯誤只有在 運行時才會發生。
比如:除數為0,數組下標越界等
2.2 編譯時與運行時異常(受檢異常與非受檢異常)
我們將Error和Exception兩種異常按編譯時與運行時再細分,可分為編譯時異常和運行時異常,編譯時異常可稱為(checked)受檢異常,運行時異常可稱為(unchecked)非受檢異常。
- 指編譯器不要求強制處置的異常。一般是指編程時的邏輯錯誤,是程序員應該積極避免其出現的異常。java.lang.RuntimeException類及它的子類都是運行時異常。
- 對于這類異常,可以不作處理,因為這類異常很普遍,若全處理可能會對程序的可讀性和運行效率產生影響。
- 指編譯器要求必須處置的異常。即程序在運行時由于外界因素造成的一般性異常。編譯器要求Java程序必須捕獲或聲明所有編譯時異常。
- 對于這類異常,如果程序不處理,可能會帶來意想不到的結果。
3.常見的具體異常
以下舉幾個常見的異常,可以在main方法中自行測試
public class ExceptionTest {/************ 以下是編譯時異常 ************/public void test7(){File file = new File("hello.txt");//當前目錄下無hello.txt文件就會報異常//FileNotFoundException FileInputStream fis = new FileInputStream(file);int data = fis.read();while(data != -1){System.out.print((char)data);data = fis.read();}fis.close();}/************ 以下是運行時異常 ************///ArithmeticException public void test6(){int a = 10;int b = 0;System.out.println(a / b);//除數不能為0}//InputMismatchException public void test5(){Scanner scanner = new Scanner(System.in);int score = scanner.nextInt();//輸入不匹配異常,假設輸入的是字符串System.out.println(score);scanner.close();}//NumberFormatException public void test4(){String str = "123";str = "abc";int num = Integer.parseInt(str);//數據格式轉換異常,字符串為非數字不能抓換為數字}//ClassCastExceptionpublic void test3(){Object obj = new Date();String str = (String)obj;//類的強制類型轉換異常}//IndexOutOfBoundsException 索引越界異常public void test2(){//ArrayIndexOutOfBoundsException int[] arr = new int[10];System.out.println(arr[10]);//數組索引越界異常//StringIndexOutOfBoundsExceptionString str = "abc";System.out.println(str.charAt(3));//字符串索引越界異常}//NullPointerExceptionpublic void test1(){int[] arr = null;System.out.println(arr[3]);String str = "abc";str = null;System.out.println(str.charAt(0));//str為null,空指針異常} }4.如何處理異常?
- 在編寫程序時,經常要在可能出現錯誤的地方加上檢測的代碼,如進行x/y運算時,要檢測分母為0,數據為空,輸入的不是數據而是字符等。過多的if-else分支會導致程序的代碼加長、臃腫,可讀性差。因此采用異常處理機制。
- Java采用的異常處理機制,是將異常處理的程序代碼集中在一起,與正常的程序代碼分開,使得程序簡潔、優雅,并易于維護。
- Java異常處理的方式有一下幾種:
- 代碼中捕獲異常:try-catch-finally
- 方法后面聲明異常:throws + 異常類型
- 手動拋出異常:throw +異常對象
- 自定義異常
4.1 異常的處理機制
異常的處理:抓拋模型
-
"拋":程序的執行過程中如出現異常,會生成一個異常類對象,該異常對象將被拋給Java運行時系統,這個過程稱為拋出(throw)異常。一旦拋出對象以后,其后的代碼就不再執行。
關于異常對象的產生:
① 由虛擬機自動生成:程序運行過程中,虛擬機檢測到程序發生了問題,如果在當前代碼中沒有找到相應的處理程序,就會在后臺自動創建一個對應異常類的實例對象并拋出——自動拋出② 由開發人員 手動創建,手動的生成一個異常對象,并拋出(throw)
-
"抓":可以理解為異常的處理方式:① try-catch-finally ② throws+ 異常類型
異常的拋出機制:
- 如果一個方法內拋出異常,該異常對象會被拋給調用者方法中處理。如果異常沒有在調用者方法中處理,它繼續被拋給這個調用方法的上層方法。這個過程將一直繼續下去,直到異常被處理。這一過程稱為捕獲(catch)異常。
- 如果一個異常回到main()方法,并且main()也不處理,則程序運行終止。
- 程序員通常只能處理Exception,而對Error無能為力。
接下來舉幾個例子,具體的用java提供的方法來處理一些異常。
4.2 代碼中捕獲異常:try-catch-finally
try-catch-finally語法:
try{ ...... //可能產生異常的代碼 } catch( ExceptionName1 e ){ ...... //當產生ExceptionName1型異常時的處置措施 } catch( ExceptionName2 e ){ ...... //當產生ExceptionName2型異常時的處置措施 } [ finally{ ...... //無論是否發生異常, 都無條件執行的語句 ***finally可要可不要*** } ]try:
捕獲異常的第一步是用try{…}語句塊選定捕獲異常的范圍,將可能出現異常的代碼放在try語句塊中。
catch (Exceptiontype e):
在catch語句塊中是對異常對象進行處理的代碼。每個try語句塊可以伴隨一個或多個catch語句,用于處理可能產生的不同類型的異常對象。
如果明確知道產生的是何種異常,可以用該異常類作為catch的參數;也可以用其父類作為catch的參數。
比 如 : 可 以 用 ArithmeticException 類 作 為 參 數 的 地 方 , 就 可 以 用RuntimeException類作為參數,或者用所有異常的父類Exception類作為參數。但不能是與ArithmeticException類無關的異常,如NullPointerException(catch中的語句將不會執行)。
我們可以在cath中使用異常對象的一些方法來捕獲異常的有關信息。
下面的是 Throwable 類的主要方法:
finally:
- 捕獲異常的最后一步是通過finally語句為異常處理提供一個統一的出口,使得在控制流轉到程序的其它部分以前,能夠對程序的狀態作統一的管理。像數據庫連接、輸入輸出流、網絡編程Socket等資源,JVM是不能自動的回收的,我們需要自己手動的進行資源的釋放。此時的資源釋放,就需要聲明在finally中。
- 不論在try代碼塊中是否發生了異常事件,catch語句是否執行,catch語句是否有異常,catch語句中是否有return,finally塊中的語句都會被執行。
- finally語句和catch語句是任選的
運行結果:
進入方法A 用A方法的finally 制造異常 進入方法B 調用B方法的finally下面舉一個try-catch-finally的例子:
public class ExceptionTest {public static void main(String[] args) {String str = "123";str = "abc";int num = 0;try{System.out.println("-----1-------");num = Integer.parseInt(str);str=null;System.out.println("-----2-------");System.out.println(str.charAt(0));}catch(NumberFormatException e){System.out.println("出現數值轉換異常了,不要著急....");System.out.println("e.getMessage()="+e.getMessage());System.out.println(e.getMessage().toString());e.printStackTrace();}catch(NullPointerException e){System.out.println("出現空指針異常了,不要著急....");}catch(Exception e){System.out.println("出現異常了,不要著急....");}System.out.println("num="+num);System.out.println("-----3--------");} }- 異常是RuntimeException類或是它的子類,這些類的異常的特點是:即使沒有使用try和catch捕獲,Java自己也能捕獲,并且編譯通過( 但運行時會發生異常使得程序運行終止 )。
- 如果拋出的異常是IOException等類型的編譯時時異常,則必須捕獲,否則編譯錯誤。也就是說,我們必須處理編譯時異常,將異常進行捕捉,轉化為運行時異常
4.3 方法中聲明拋出異常:throws + 異常類型
- 如果一個方法(中的語句執行時)可能生成某種異常,但是并不能確定如何處理這種異常,則此方法應顯示地聲明拋出異常,表明該方法將不對這些異常進行處理,而由該方法的調用者負責處理。
- 在方法聲明中用throws語句可以聲明拋出異常的列表,throws后面的異常類型可以是方法中產生的異常類型,也可以是它的父類異常類型 。
重寫方法不能拋出比被重寫方法范圍更大的異常類型。在多態的情況下,對methodA()方法的調用—異常的捕獲按父類聲明的異常處理。
public class A {public void methodA() throws IOException {} }class B1 extends A {public void methodA() throws FileNotFoundException {} }class B2 extends A {public void methodA() throws Exception { // 報錯。重寫方法不能拋出比被重寫方法范圍更大的異常類型} }開發中如何選擇使用try-catch-finally 還是使用throws?
如果父類中被重寫的方法沒有throws方式處理異常,則子類重寫的方法也不能使用throws,意味著如果子類重寫的方法中有異常,必須使用try-catch-finally方式處理。
public class A {public void methodA() {} }class B1 extends A {public void methodA() throws FileNotFoundException {//報錯} }執行的方法a中,先后又調用了另外的幾個方法,這幾個方法是遞進關系執行的。建議這幾個方法使用throws的方式進行處理。而執行的方法a可以考慮使用try-catch-finally方式進行處理。如下所示:
public class ExceptionTest{public static void main(String[] args){try{method2();}catch(IOException e){e.printStackTrace();}method3();}public static void method3(){try {method2();} catch (IOException e) {e.printStackTrace();}}public static void method2() throws IOException{method1();}public static void method1() throws FileNotFoundException,IOException{File file = new File("hello1.txt");FileInputStream fis = new FileInputStream(file);int data = fis.read();while(data != -1){System.out.print((char)data);data = fis.read();}fis.close();System.out.println("hahaha!");}}4.4 手動拋出異常:throw + 異常對象
-
Java異常類對象除在程序執行過程中出現異常時由系統自動生成并拋出,也可根據需要 使用人工 創建并拋出 。
-
首先要生成異常類對象,然后通過throw語句實現拋出操作(提交給Java運行環境)。
IOException e = new IOException(); throw e; -
可以拋出的異常必須是Throwable或其子類的實例。下面的語句在編譯時將會產生語法錯誤:
throw new String("want to throw");//Error -
可以在每個異常對象構造器中填寫要打印的異常信息。
public static void main(String[] args) {throw new RuntimeException("測試手動拋出異常"); }
4.5 自定義異常類
- 一般地,用戶自定義異常類都是RuntimeException的子類。
- 自定義異常類通常需要編寫幾個重載的構造器。
- 自定義異常需要提供serialVersionUID
- 自定義的異常通過throw拋出。
- 自定義異常最重要的是異常類的名字,當異常出現時,可以根據名字判斷異常類型。
運行結果:
不能輸入負數5.一張圖概覽關鍵字
總結
以上是生活随笔為你收集整理的一篇搞定异常: Exception的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一文总结:抽象类(abstract)与接
- 下一篇: 枚举Enum与注解Aunotation大