提及異常,我就想起了Bug,也就是常說的信春哥,無Bug,什麼是Bug呢?我理解的Bug就是沒有按照本身原先假想的邏輯去執行,這其中包括了兩個方面,一方面是代碼語法問題,一方面是邏輯問題,就好比正常邏輯買了東西要付款,可是買家買了東西卻沒有付款,直接拿東西走了,這是邏輯問題,或者是原本數組存儲3個元素,你卻存了4個,這時候也出現了Bug,程序報錯了,這種Bug就是異常。
異常也是Java類的一種,用new建立對象,他們的結構是這樣的:java
Throwable程序員
error面試
Exception編程
恩,就是這樣,異常分爲錯誤和異常,感受有點繞口,但就是這樣,像error這種錯誤是在編譯期間就會報出來的,若是你使用的是IDE,因此咱們只須要關注Exception異常就能夠了。數組
獲取和處理異常可能就是異常的所有,咱們的一個原則就是:學習
發生異常就得讓程序員知道this
怎麼獲取異常呢?Java給出了try關鍵字用來解決,咱們只須要將可能出現異常的代碼放在try中就能夠了,就像這樣:日誌
try{ ... }
java給出了儘可能優雅的解決方案來處理異常,它不但願處理異常的代碼和自己的業務代碼有過多的混合,獲取到異常就該處理異常,這時候就應該這樣寫了:code
try{ ... }catch(Type1 type1){ ... }catch(Type2 type2){ ... }
catch中的type表明了在try中可能出現的異常類型對象
catch如何匹配異常?
按順序從第一個到最後一個,若是發現異常匹配,就中止匹配,和switch模式不同
基類包含子類異常,若是第一個是Exception,那麼後面的都不用匹配了
那麼catch中怎麼處理這個異常呢?
不做處理(會出現「吞食」)
打印到控制檯
寫入日誌
繼續向上拋
在try塊中拋出異常,咱們在catch中會匹配到相應的異常類型,這時候咱們就會拿到對應的異常對象的引用,咱們調用throwalbe的方法用於處理:
public class ExceptionMethods { public static void main(String[] args) { try { throw new Exception("My Exception"); } catch (Exception e) { System.out.println("Caught Exception"); System.out.println(e.getMessage()); System.out.println(e.getLocalizedMessage()); System.out.println(e); System.out.println(e.toString()); e.printStackTrace(); e.printStackTrace(System.out); } } }
咱們通常使用e.printStackTrace();打出異常棧信息便可
或者是寫入Log,使用logger.error
每一個人處理處理異常的方式可能不盡相同
咱們除了可使用try來捕獲異常,咱們也能夠將這個異常拋出去,咱們能夠把異常比做如今這種制度,地球村出了點問題,村長衡量了一下,以爲這事情本身處理不了,就交給鄉長了,這種把問題交給上層或者是Java編程思想中說的跳出當前環境,交給一個更大的環境去處理,這也是Java異常處理的一種思路。
if(t == null) throw new NullPointerException();
其實異常最重要的就是異常的名稱,如今Java正在擴充異常的種類,可是不少異常可能不是咱們想要的,那麼咱們就能夠自定義異常:
class SystemErrException extends Exception{ }
這就是一個異常類,咱們繼承了Exception,這個SysteErrException就能夠用於咱們處理異常的時候了,固然咱們能夠給他加點參數:
class SystemErrException extends Exception{ public SystemErrException(){ } public SystemErrException (String message){ super(message); } }
或者是這樣:
class SystemErrException extends Exception{ private int i; public SystemErrException(){ } public SystemErrException (String message){ super(message); } public SystemErrException (String message, int i){ super(message); this.i = i; } }
這只不過是多加了幾個參數,可是這些通常是沒什麼必要的。
說到這,就得說另外一個關鍵字throws,看清楚,不是throw,而是throws,這可能也是面試新手的時候會問的一個問題,throws是異常中的一個申明,在IO學習中會很是常見,它是一個聲明,編譯器檢查到說你這段代碼可能會發生什麼異常,你要聲明一下,這時候你就要在方法上聲明:
public void inputFile() throws IOException{ .... }
finally用處就和他的意思相符,表示最終的含義,也就是finally裏面的代碼必定會獲得執行:
案例一
public class FinallyException { static int count = 0; public static void main(String[] args) { while (true){ try { if (count++ == 0){ throw new ThreeException(); } System.out.println("no Exception"); }catch (ThreeException e){ System.out.println("ThreeException"); }finally { System.out.println("in finally cause"); if(count == 2) break; } } } } class ThreeException extends Exception{ }
執行結果:
ThreeException in finally cause no Exception in finally cause
案例二:return案例
public class MultipleReturns { public static void f(int i){ System.out.println("start......."); try { System.out.println("1"); if(i == 1) return; System.out.println("2"); if (i == 2) return; System.out.println("3"); if(i == 3) return; System.out.println("else"); return; }finally { System.out.println("end"); } } public static void main(String[] args) { for (int i = 1; i<4; i++){ f(i); } } }
執行結果:
start....... 1 end start....... 1 2 end start....... 1 2 3 end
咱們可能遇到這種狀況,打開一個文件,讀取文件,關閉文件,正常邏輯是這樣的,可是這樣會有幾個問題:
在打開文件的過程當中出現異常,可是還要關閉文件
就像這樣:
try{ A a = new A(); ... }catch(){ ... }finally{ a.close(); }
A在建立過程當中會出現異常,可是仍是會執行a的方法,好比關閉文件
因此咱們應該這麼作:
try{ A a = new A(); try{ ... }finally{ a.close(); } }catch(){ ... }
通常報錯都會報一大堆錯誤,你們無從看起,其實異常報錯也是有規律的,這就是棧結構,先進後出,舉個栗子:
public class WhoCalled { static void f() { try { throw new Exception(); } catch (Exception e) { for (StackTraceElement ste : e.getStackTrace()){ System.out.println(ste.getMethodName()); } } } static void g(){ f(); } static void h(){ g(); } public static void main(String[] args) { f(); System.out.println("---------------------------"); g(); System.out.println("---------------------------"); h(); System.out.println("---------------------------"); } }
運行結果:
f main --------------------------- f g main --------------------------- f g h main ---------------------------
能夠看到異常信息都是從內到外的,按個人理解查看異常的時候要從第一條異常信息看起,由於那是異常發生的源頭。
異常總的來講仍是很重要的,也是保障程序健壯性很重要的一欄,而且能夠達到立竿見影的效果,這裏只是基本總結了異常的一些常見問題,不少還得在本身運用的過程當中去探索。