国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Java > 正文

簡單談?wù)刯ava的異常處理(Try Catch Finally)

2019-11-26 14:28:36
字體:
供稿:網(wǎng)友

異常的英文單詞是exception,字面翻譯就是“意外、例外”的意思,也就是非正常情況。事實上,異常本質(zhì)上是程序上的錯誤,包括程序邏輯錯誤和系統(tǒng)錯誤。

一 前言

java異常處理大家都不陌生,總的來說有下面兩點:

1.拋出異常:throw exception

class SimpleException{  public void a() throws Exception{    throw new Exception();  };}

2.捕獲異常:

public class MyException {  public static void main(String[] args){    MyException e = new MyException();    SimpleException se = new SimpleException();    try {      se.a();    } catch (Exception e1) {      e1.printStackTrace();    }  }}class SimpleException{  public void a() throws Exception{    throw new Exception();  };}

本文將在此基礎(chǔ)上,更加深入的談一些細節(jié)問題。

二 自定義異常類

java語言為我們提供了很多異常類,但是有時候我們?yōu)榱藢懘a的方便還是要自定義的去創(chuàng)造異常類:

class SimpleException extends Exception {};
創(chuàng)建好之后我們可以使用try catch捕獲它:

public class MyException {  public static void main(String[] args){    MyException e = new MyException();    try {      e.a();    } catch (SimpleException e1) {      e1.printStackTrace();    }  }    public void a() throws SimpleException{    throw new SimpleException();  }}class SimpleException extends Exception {};

我們在MyException中定義了一個方法a(),讓它拋出SimpleException異常,然后我們在main()中調(diào)用這個方法,并使用try catch捕獲了這個異常:

SimpleException  at MyException.a(MyException.java:15)  at MyException.main(MyException.java:8)  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)  at java.lang.reflect.Method.invoke(Method.java:606)  at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)Process finished with exit code 0

編譯執(zhí)行后的結(jié)果,主要看前三行就行了。這里著重說明幾點:
1.拋出異常類型的指定:(exception specification)
當我們需要在一個方法中拋出一個異常時,我們使用throw后加某異常類的實例,程序會在此向客戶端程序(調(diào)用這段代碼的程序)拋出對應(yīng)異常并在此退出(相當于return)。另外需要注意的是,我們必須在定義該方法的時候指明異常類型,比如下面這段代碼會拋出SimpleException異常

public void a() throws SimpleException

2.拋出多個異常:

  public void a() throws SimpleException,AException,BException{    throw new SimpleException();      }

不同的異常類之間用逗號隔開即可,在這種情況下我們不必須throw每個異常類的實例(),但是客戶端代碼必須要catch到每個異常類:

public class MyException {  public static void main(String[] args){    MyException e = new MyException();    try {      e.a();    } catch (SimpleException e1) {      e1.printStackTrace();    } catch (BException e1) {      e1.printStackTrace();    } catch (AException e1) {      e1.printStackTrace();    }  }  public void a() throws SimpleException,AException,BException{    throw new SimpleException();      }}class SimpleException extends Exception {};class AException extends Exception{}class BException extends Exception{}

三 stack trace

無論是拋出異常,或者是捕獲處理異常,我們的目的是為了寫出更健壯的程序,這很大程度上依賴于java異常機制給我們提供的異常信息,而它的載體就是stack trace。
前面的代碼中我們直接使用printStackTrace()打印出異常信息,其實我們還可以使用getStackTrace()方法來獲取StackTraceElement型的集合,如果你手頭有IDEA的話,你可以先搜索出StackTraceElement類,可以發(fā)現(xiàn)它實現(xiàn)了接口Serializable ,再看看它的類描述:

/** * An element in a stack trace, as returned by {@link * Throwable#getStackTrace()}. Each element represents a single stack frame. * All stack frames except for the one at the top of the stack represent * a method invocation. The frame at the top of the stack represents the * execution point at which the stack trace was generated. Typically, * this is the point at which the throwable corresponding to the stack trace * was created. * * @since 1.4 * @author Josh Bloch */

講的很清楚,這個類的每個實例都是stack trace的一個元素,代表著一個stack frame,stack trace是由getStackTrace()方法返回的。后邊的我試著翻譯了幾遍,都覺得不好,還是直接上代碼才能說清楚:

public class MyException {  public static void main(String[] args){    MyException e = new MyException();    e.a();  public void a(){    try {      throw new Exception();    } catch (Exception e) {      StackTraceElement[] ste = e.getStackTrace();      System.out.println(ste.length);    }  }}

我們定義了方法a,讓它拋出Exception異常的同時捕獲它,然后我們通過getStackTrace()方法得到一個StackTraceElement型的數(shù)組,并打印出數(shù)組的長度:

7

Process finished with exit code 0
我們把代碼稍微改一下,不在a中捕獲異常了,我們重新定義一個方法b,讓它在調(diào)用a的同時將異常捕獲:

public class MyException {  public static void main(String[] args){    MyException e = new MyException();    e.b();  }  public void b(){    try {      a();    } catch (Exception e) {      StackTraceElement[] ste = e.getStackTrace();      System.out.println(ste.length);    }  }  public void a() throws Exception{    throw new Exception();  }}

結(jié)果如下:

8

Process finished with exit code 0
別急,我們再來看點有趣的:

public class MyException {  public static void main(String[] args){    MyException exception = new MyException();    try {      exception.c();    } catch (Exception e) {      StackTraceElement[] ste = e.getStackTrace();      System.out.println(ste.length);      System.out.println("---------------------------------------------------------------");      for (StackTraceElement s : e.getStackTrace()){        System.out.println(s.getClassName()+":method "+s.getMethodName()+" at line"+s.getLineNumber());      }      System.out.println("---------------------------------------------------------------");    }  } public void c() throws Exception{    try {      a();    }catch (Exception e){      throw e;    }  }  public void a() throws Exception{    throw new Exception();  }}

下面是結(jié)果:

8---------------------------------------------------------------MyException:method a at line43MyException:method c at line39MyException:method main at line9sun.reflect.NativeMethodAccessorImpl:method invoke0 at line-2sun.reflect.NativeMethodAccessorImpl:method invoke at line57sun.reflect.DelegatingMethodAccessorImpl:method invoke at line43java.lang.reflect.Method:method invoke at line606com.intellij.rt.execution.application.AppMain:method main at line144---------------------------------------------------------------Process finished with exit code 0

也就是說,getStackTrace()返回一個棧,它包含從調(diào)用者(main())到初始拋出異常者(a())的一些基本信息 ,在上面的代碼中,我們在c方法中調(diào)用a方法時捕獲異常并通過throws將其再次拋出(rethrow),調(diào)用c方法的方法可以捕獲并處理異常,也可以選擇繼續(xù)拋出讓更高層次的調(diào)用者(靠近棧底)處理。rethrow雖然很方便,但存在著一些問題,我們看下面這段代碼:

public class MyException {  public static void main(String[] args){    MyException exception = new MyException();    try {      exception.c();    } catch (Exception e) {      e.printStackTrace(System.out);    }  }  public void c() throws Exception{    try {      a();    }catch (Exception e){      throw e;    }  }  public void a() throws Exception{    throw new Exception("Exception from a()");  }}java.lang.Exception: Exception from a()  at MyException.a(MyException.java:40)  at MyException.c(MyException.java:30)  at MyException.main(MyException.java:21)

我們在c中重新拋出e,在main中使用 e.printStackTrace()打印出來,可以看到打印出來stack trace還是屬于a的,如果我們想把stack trace變成c的可以這么寫:

public class MyException {  public static void main(String[] args){    MyException exception = new MyException();    try {      exception.c();    } catch (Exception e) {      e.printStackTrace(System.out);    }  }  public void c() throws Exception{    try {      a();    }catch (Exception e){//      throw e;      throw (Exception)e.fillInStackTrace();    }  }  public void a() throws Exception{    throw new Exception("Exception from a()");  }}java.lang.Exception: Exception from a()  at MyException.c(MyException.java:22)  at MyException.main(MyException.java:10)

四 異常鏈 Exception chaining

先來看一個場景:

public class TestException {  public static void main(String[] args){    TestException testException = new TestException();    try {      testException.c();    } catch (CException e) {      e.printStackTrace();    }  }  public void a() throws AException{    AException aException = new AException("this is a exception");    throw aException;  }  public void b() throws BException{    try {      a();    } catch (AException e) {      throw new BException("this is b exception");    }  }  public void c() throws CException{    try {      b();    } catch (BException e) {      throw new CException("this is c exception");    }  }}class AException extends Exception{  public AException(String msg){    super(msg);  }}class BException extends Exception{  public BException(String msg){    super(msg);  }}class CException extends Exception{  public CException(String msg){    super(msg);  }}

創(chuàng)建了三個異常類AException、BException、CException,然后在a()中拋出AException,在b()中捕獲AException并拋出BException,最后在c()中捕獲BException并拋出CException,結(jié)果打印如下:

CException: this is c exception  at TestException.c(TestException.java:31)  at TestException.main(TestException.java:8)

好,我們只看到了CException的信息,AException,BException的異常信息已丟失,這時候異常鏈的作用就出來了,看代碼:

public class TestException {  public static void main(String[] args){    TestException testException = new TestException();    try {      testException.c();    } catch (CException e) {      e.printStackTrace();    }  }  public void a() throws AException{    AException aException = new AException("this is a exception");    throw aException;  }  public void b() throws BException{    try {      a();    } catch (AException e) {//      throw new BException("this is b exception");      BException bException = new BException("this is b exception");      bException.initCause(e);      throw bException;    }  }  public void c() throws CException{    try {      b();    } catch (BException e) {//      throw new CException("this is c exception");      CException cException = new CException("this is c exception");      cException.initCause(e);      throw cException;    }  }}class AException extends Exception{  public AException(String msg){    super(msg);  }}class BException extends Exception{  public BException(String msg){    super(msg);  }}class CException extends Exception{  public CException(String msg){    super(msg);  }}

我們用initCause()方法將異常信息給串聯(lián)了起來,結(jié)果如下:

CException: this is c exception  at TestException.c(TestException.java:35)  at TestException.main(TestException.java:8)  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)  at java.lang.reflect.Method.invoke(Method.java:606)  at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)Caused by: BException: this is b exception  at TestException.b(TestException.java:24)  at TestException.c(TestException.java:32)  ... 6 moreCaused by: AException: this is a exception  at TestException.a(TestException.java:15)  at TestException.b(TestException.java:21)  ... 7 moreProcess finished with exit code 0

五 后記

其實關(guān)于java異常處理還有很多需要探討的地方,但是由于我經(jīng)驗有限,還不能體會的太深刻,最常用的也就是

try {      ...    }catch (Exception e){      ...     }finally {     //不管異常會不會被捕捉或者處理都會執(zhí)行的代碼,如關(guān)閉IO操作     }

但是無論如何我們還是要感謝java給我們提供的異常機制,它好似一個長者,時不時給我們指引道路,也讓我們在編碼的時候沒有那么無聊:)

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 漠河县| 开平市| 丹东市| 马关县| 洪江市| 镇赉县| 五华县| 科尔| 台南市| 新津县| 商洛市| 巴里| 青河县| 黔江区| 滦南县| 盐山县| 安阳市| 青浦区| 合山市| 财经| 弥勒县| 彭山县| 松原市| 达日县| 浮梁县| 上高县| 汉寿县| 繁昌县| 长白| 衡南县| 措勤县| 普洱| 左云县| 额敏县| 镇坪县| 武隆县| 梨树县| 高邑县| 苍梧县| 万荣县| 闽侯县|