總結了Java異常十個關鍵知識點,面試或者工做中都有用哦,加油。java
異常是指阻止當前方法或做用域繼續執行的問題。好比你讀取的文件不存在,數組越界,進行除法時,除數爲0等都會致使異常。程序員
一個文件找不到的異常:面試
public class TestException { public static void main(String[] args) throws IOException { InputStream is = new FileInputStream("jaywei.txt"); int b; while ((b = is.read()) != -1) { } } }
運行結果:sql
Exception in thread "main" java.io.FileNotFoundException: jaywei.txt (系統找不到指定的文件。) at java.io.FileInputStream.open0(Native Method) at java.io.FileInputStream.open(FileInputStream.java:195) at java.io.FileInputStream.<init>(FileInputStream.java:138) at java.io.FileInputStream.<init>(FileInputStream.java:93) at exception.TestException.main(TestException.java:10)
從前從前,有位老人,他的名字叫Throwable,他生了兩個兒子,大兒子叫Error,二兒子叫Exception。數據庫
表示編譯時或者系統錯誤,如虛擬機相關的錯誤,OutOfMemoryError等,error是沒法處理的。數組
代碼異常,Java程序員關心的基類型一般是Exception。它能被程序自己能夠處理,這也是它跟Error的區別。ide
它能夠分爲RuntimeException(運行時異常)和CheckedException(可檢查的異常)。函數
常見的RuntimeException異常:學習
- NullPointerException 空指針異常 - ArithmeticException 出現異常的運算條件時,拋出此異常 - IndexOutOfBoundsException 數組索引越界異常 - ClassNotFoundException 找不到類異常 - IllegalArgumentException(非法參數異常)
常見的 Checked Exception 異常:測試
- IOException (操做輸入流和輸出流時可能出現的異常) - ClassCastException(類型轉換異常類)
當異常出現後,會在堆上建立異常對象。當前的執行路徑被終止,而且從當前環境中彈出對異常對象的引用。這時候異常處理程序,使程序從錯誤狀態恢復,使程序繼續運行下去。
異常處理主要有拋出異常、捕獲異常、聲明異常。如圖:
try{ // 程序代碼 }catch(Exception e){ //Catch 塊 }finaly{ //不管如何,都會執行的代碼塊 }
咱們能夠經過try...catch...
捕獲異常代碼,再經過finaly
執行最後的操做,如關閉流等操做。
除了try...catch...
捕獲異常,咱們還能夠經過throws聲明拋出異常。
當你定義了一個方法時,能夠用throws
關鍵字聲明。使用了throws
關鍵字代表,該方法不處理異常,而是把異常留給它的調用者處理。是否是以爲TA不負責任?
哈哈,看一下demo吧
//該方法經過throws聲明瞭IO異常。 private void readFile() throws IOException { InputStream is = new FileInputStream("jaywei.txt"); int b; while ((b = is.read()) != -1) { } }
從方法中聲明拋出的任何異常都必須使用throws子句。
throw關鍵字做用是拋出一個Throwable
類型的異常,它通常出如今函數體中。在異常處理中,try語句要捕獲的是一個異常對象,其實此異常對象也能夠本身拋出。
例如拋出一個 RuntimeException 類的異常對象:
throw new RuntimeException(e);
任何Java代碼均可以經過 Java 的throw語句拋出異常。
try-catch-finally-return 執行描述
看一個例子
public static void main(String[] args) throws IOException { System.out.println("result:" + test()); } private static int test() { int temp = 1; try { System.out.println("start execute try,temp is:"+temp); return ++temp; } catch (Exception e) { System.out.println("start execute catch temp is: "+temp); return ++temp; } finally { System.out.println("start execute finally,temp is:" + temp); ++temp; } }
運行結果:
start execute try,temp is:1 start execute finally,temp is:2 result:2
分析
++temp
表達式,temp變爲2,這個值被保存起來。++temp
表達式.先來喵一眼異常類的全部方法,以下圖:
Returns the detail message string of this throwable.
getMessage會返回Throwable的detailMessage
屬性,而detailMessage
就表示發生異常的詳細消息描述。
舉個例子,FileNotFoundException
異常發生時,這個detailMessage
就包含這個找不到文件的名字。
Creates a localized description of this throwable.Subclasses may override this method in order to produce alocale-specific message. For subclasses that do not override thismethod, the default implementation returns the same result as getMessage()
throwable的本地化描述。子類能夠重寫此方法,以生成特定於語言環境的消息。對於不覆蓋此方法的子類,默認實現返回與相同的結果 getMessage()。
Returns the cause of this throwable or null if thecause is nonexistent or unknown.
返回此可拋出事件的緣由,或者,若是緣由不存在或未知,返回null。
Prints this throwable and its backtrace to thestandard error stream. The first line of output contains the result of the toString() method for this object.Remaining lines represent data previously recorded by the method fillInStackTrace().
該方法將堆棧跟蹤信息打印到標準錯誤流。
輸出的第一行,包含此對象toString()方法的結果。剩餘的行表示,先前被方法fillInStackTrace()記錄的數據。以下例子:
java.lang.NullPointerException at MyClass.mash(MyClass.java:9) at MyClass.crunch(MyClass.java:6) at MyClass.main(MyClass.java:3)
自定義異常一般是定義一個繼承自 Exception 類的子類。
那麼,爲何須要自定義異常?
下面是我司自定義異常類的一個簡單demo
public class BizException extends Exception { //錯誤信息 private String message; //錯誤碼 private String errorCode; public BizException() { } public BizException(String message, String errorCode) { this.message = message; this.errorCode = errorCode; } @Override public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public String getErrorCode() { return errorCode; } public void setErrorCode(String errorCode) { this.errorCode = errorCode; } }
跑個main方測試一下
public class TestBizException { public static void testBizException() throws BizException { System.out.println("throwing BizException from testBizException()"); throw new BizException("100","哥,我錯了"); } public static void main(String[] args) { try { testBizException(); } catch (BizException e) { System.out.println("本身定義的異常"); e.printStackTrace(); } } }
運行結果:
exception.BizException: 100 throwing BizException from testBizException() 本身定義的異常 at exception.TestBizException.testBizException(TestBizException.java:7) at exception.TestBizException.main(TestBizException.java:12)
try-with-resources,是Java7提供的一個新功能,它用於自動資源管理。
在try-with-resources
出現以前
try{ //open resources like File, Database connection, Sockets etc } catch (FileNotFoundException e) { // Exception handling like FileNotFoundException, IOException etc }finally{ // close resources }
Java7,try-with-resources
出現以後,使用資源實現
try(// open resources here){ // use resources } catch (FileNotFoundException e) { // exception handling } // resources are closed as soon as try-catch block is executed.
Java7使用資源demo
public class Java7TryResourceTest { public static void main(String[] args) { try (BufferedReader br = new BufferedReader(new FileReader( "C:/jaywei.txt"))) { System.out.println(br.readLine()); } catch (IOException e) { e.printStackTrace(); } } }
使用了try-with-resources
的好處
咱們經常會想要在捕獲一個異常後拋出另外一個異常,而且但願把原始異常的信息保存下來,這被稱爲異常鏈。
throw
拋出的是一個新的異常信息,這樣會致使原有的異常信息丟失。在JDk1.4之前,程序員必須本身編寫代碼來保存原始異常信息。如今全部Throwable
子類在構造器中均可以接受一個cause(異常因由)
對象做爲參數。
這個cause
就用來表示原始異常,這樣經過把原始異常傳遞給新的異常,使得即便當前位置建立並拋出了新的異常,也能經過這個異常鏈追蹤到異常最初發生的位置。
使用方式以下:
public class TestChainException { public void readFile() throws MyException{ try { InputStream is = new FileInputStream("jay.txt"); Scanner in = new Scanner(is); while (in.hasNext()) { System.out.println(in.next()); } } catch (FileNotFoundException e) { //e 保存異常信息 throw new MyException("文件在哪裏呢", e); } } public void invokeReadFile() throws MyException{ try { readFile(); } catch (MyException e) { //e 保存異常信息 throw new MyException("文件找不到", e); } } public static void main(String[] args) { TestChainException t = new TestChainException(); try { t.invokeReadFile(); } catch (MyException e) { e.printStackTrace(); } } } //MyException 構造器 public MyException(String message, Throwable cause) { super(message, cause); }
運行結果:
咱們能夠看到異常信息有保存下來的,若是把cause(也就是FileNotFoundException 的e)去掉呢,看一下運行結果:
能夠發現,少了Throwable cause
,原始異常信息不知去向了。
拋出異常的時候,異常處理系統會按照代碼的書寫順序找出"最近"的處理程序。 找到匹配的處理程序以後,它就認爲異常將獲得處理,而後就再也不繼續查找。
查找的時候並不要求拋出的異常同處理程序的異常徹底匹配。派生類的對象也能夠配備其基類的處理程序
看demo
package exceptions; //: exceptions/Human.java // Catching exception hierarchies. class Annoyance extends Exception {} class Sneeze extends Annoyance {} public class Human { public static void main(String[] args) { // Catch the exact type: try { throw new Sneeze(); } catch(Sneeze s) { System.out.println("Caught Sneeze"); } catch(Annoyance a) { System.out.println("Caught Annoyance"); } // Catch the base type: try { throw new Sneeze(); } catch(Annoyance a) { System.out.println("Caught Annoyance"); } } }
運行結果:
catch(Annoyance a)會捕獲Annoyance以及全部從它派生的異常。
捕獲基類的異常,就能夠匹配全部派生類的異常
try { throw new Sneeze(); } catch(Annoyance a) { } catch(Sneeze s) { //這句編譯器會報錯,由於異常已由前面catch子句處理 }
空指針異常,最多見的一個異常類。簡言之,調用了未經初始化的對象或者是不存在的對象,就會產生該異常。
算術異常類,程序中出現了除數爲0這樣的運算,就會出現這樣的異常。
類型強制轉換異常,它是JVM在檢測到兩個類型間轉換不兼容時引起的運行時異常。
數組下標越界異常,跟數組打交道時,須要注意一下這個異常。
文件未找到異常,通常是要讀或者寫的文件,找不到,致使該異常。
操做數據庫異常,它是Checked Exception(檢查異常);
IO異常,通常跟讀寫文件息息相關,它也是Checked Exception(檢查異常)。平時讀寫文件,記得IO流關閉!
方法未找到異常
字符串轉換爲數字異常
這個總結獨闢蹊徑,以幾道經典異常面試題結束吧,以幫助你們複習一下,嘻嘻。